Improve decoding of mount flags #172

Merged
merged 4 commits into from Oct 19, 2016
Jump to file or symbol
Failed to load files and symbols.
+258 −48
Split
View
@@ -2,6 +2,7 @@ src/snap-confine
src/snap-discard-ns
src/snap-confine-unit-tests
src/snap-confine.apparmor
+src/decode-mount-opts
*~
*.o
View
@@ -1,8 +1,14 @@
libexec_PROGRAMS = snap-confine snap-discard-ns
+noinst_PROGRAMS = decode-mount-opts
if WITH_UNIT_TESTS
-noinst_PROGRAMS = snap-confine-unit-tests
+noinst_PROGRAMS += snap-confine-unit-tests
endif
+decode_mount_opts_SOURCES = \
+ decode-mount-opts.c \
+ mount-opt.c \
+ mount-opt.h
+
snap_discard_ns_SOURCES = \
ns-support.c \
ns-support.h \
@@ -52,6 +58,8 @@ snap_confine_SOURCES = \
user-support.h \
quirks.c \
quirks.h \
+ mount-opt.c \
+ mount-opt.h \
mountinfo.c \
mountinfo.h \
ns-support.c \
@@ -97,7 +105,8 @@ snap_confine_unit_tests_SOURCES = \
mount-support-test.c \
verify-executable-name-test.c \
mountinfo-test.c \
- ns-support-test.c
+ ns-support-test.c \
+ mount-opt-test.c
snap_confine_unit_tests_CFLAGS = $(snap_confine_CFLAGS) $(GLIB_CFLAGS)
snap_confine_unit_tests_LDADD = $(snap_confine_LDADD) $(GLIB_LIBS)
snap_confine_unit_tests_LDFLAGS = $(snap_confine_LDFLAGS)
View
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mount-opt.h"
+
+int main(int argc, char *argv[])
+{
+ if (argc != 2) {
+ printf("usage: decode-mount-opts OPT\n");
+ return 0;
+ }
+ char *end;
+ unsigned long mountflags = strtoul(argv[1], &end, 0);
+ if (*end != '\0') {
+ fprintf(stderr, "cannot parse given argument as a number\n");
+ return 1;
+ }
+ printf("%#lx is %s\n", mountflags, sc_mount_opt2str(mountflags));
+ return 0;
+}
View
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mount-opt.h"
+#include "mount-opt.c"
+
+#include <sys/mount.h>
+#include <glib.h>
+
+static void test_sc_mount_opt2str()
+{
+ g_assert_cmpstr(sc_mount_opt2str(0), ==, "");
+ g_assert_cmpstr(sc_mount_opt2str(MS_RDONLY), ==, "ro");
+ g_assert_cmpstr(sc_mount_opt2str(MS_NOSUID), ==, "nosuid");
+ g_assert_cmpstr(sc_mount_opt2str(MS_NODEV), ==, "nodev");
+ g_assert_cmpstr(sc_mount_opt2str(MS_NOEXEC), ==, "noexec");
+ g_assert_cmpstr(sc_mount_opt2str(MS_SYNCHRONOUS), ==, "sync");
+ g_assert_cmpstr(sc_mount_opt2str(MS_REMOUNT), ==, "remount");
+ g_assert_cmpstr(sc_mount_opt2str(MS_MANDLOCK), ==, "mand");
+ g_assert_cmpstr(sc_mount_opt2str(MS_DIRSYNC), ==, "dirsync");
+ g_assert_cmpstr(sc_mount_opt2str(MS_NOATIME), ==, "noatime");
+ g_assert_cmpstr(sc_mount_opt2str(MS_NODIRATIME), ==, "nodiratime");
+ g_assert_cmpstr(sc_mount_opt2str(MS_BIND), ==, "bind");
+ g_assert_cmpstr(sc_mount_opt2str(MS_REC | MS_BIND), ==, "rbind");
+ g_assert_cmpstr(sc_mount_opt2str(MS_MOVE), ==, "move");
+ g_assert_cmpstr(sc_mount_opt2str(MS_SILENT), ==, "silent");
+ g_assert_cmpstr(sc_mount_opt2str(MS_POSIXACL), ==, "acl");
+ g_assert_cmpstr(sc_mount_opt2str(MS_UNBINDABLE), ==, "unbindable");
+ g_assert_cmpstr(sc_mount_opt2str(MS_PRIVATE), ==, "private");
+ g_assert_cmpstr(sc_mount_opt2str(MS_REC | MS_PRIVATE), ==, "rprivate");
+ g_assert_cmpstr(sc_mount_opt2str(MS_SLAVE), ==, "slave");
+ g_assert_cmpstr(sc_mount_opt2str(MS_REC | MS_SLAVE), ==, "rslave");
+ g_assert_cmpstr(sc_mount_opt2str(MS_SHARED), ==, "shared");
+ g_assert_cmpstr(sc_mount_opt2str(MS_REC | MS_SHARED), ==, "rshared");
+ g_assert_cmpstr(sc_mount_opt2str(MS_RELATIME), ==, "relatime");
+ g_assert_cmpstr(sc_mount_opt2str(MS_KERNMOUNT), ==, "kernmount");
+ g_assert_cmpstr(sc_mount_opt2str(MS_I_VERSION), ==, "iversion");
+ g_assert_cmpstr(sc_mount_opt2str(MS_STRICTATIME), ==, "strictatime");
+ g_assert_cmpstr(sc_mount_opt2str(MS_LAZYTIME), ==, "lazytime");
+ // MS_NOSEC is not defined in userspace
+ // MS_BORN is not defined in userspace
+ g_assert_cmpstr(sc_mount_opt2str(MS_ACTIVE), ==, "active");
+ g_assert_cmpstr(sc_mount_opt2str(MS_NOUSER), ==, "nouser");
+ g_assert_cmpstr(sc_mount_opt2str(0x300), ==, "0x300");
+ // random compositions do work
+ g_assert_cmpstr(sc_mount_opt2str(MS_RDONLY | MS_NOEXEC | MS_BIND), ==, "ro,noexec,bind");
+}
+
+static void __attribute__ ((constructor)) init()
+{
+ g_test_add_func("/mount/sc_mount_opt2str", test_sc_mount_opt2str);
+}
View
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mount-opt.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/mount.h>
+
+const char *sc_mount_opt2str(unsigned long flags)
+{
+ static char buf[1000];
+ unsigned long used = 0;
+ strcpy(buf, "");
+#define F(FLAG, TEXT) do if (flags & (FLAG)) { strcat(buf, #TEXT ","); flags ^= (FLAG); } while (0)
+ F(MS_RDONLY, ro);
+ F(MS_NOSUID, nosuid);
+ F(MS_NODEV, nodev);
+ F(MS_NOEXEC, noexec);
+ F(MS_SYNCHRONOUS, sync);
+ F(MS_REMOUNT, remount);
+ F(MS_MANDLOCK, mand);
+ F(MS_DIRSYNC, dirsync);
+ F(MS_NOATIME, noatime);
+ F(MS_NODIRATIME, nodiratime);
+ if (flags & MS_BIND) {
+ if (flags & MS_REC) {
+ strcat(buf, "rbind,");
+ used |= MS_REC;
+ } else {
+ strcat(buf, "bind,");
+ }
+ flags ^= MS_BIND;
+ }
+ F(MS_MOVE, move);
+ // The MS_REC flag handled separately by affected flags (MS_BIND,
+ // MS_PRIVATE, MS_SLAVE, MS_SHARED)
+ // XXX: kernel has MS_VERBOSE, glibc has MS_SILENT, both use the same constant
+ F(MS_SILENT, silent);
+ F(MS_POSIXACL, acl);
+ F(MS_UNBINDABLE, unbindable);
+ if (flags & MS_PRIVATE) {
+ if (flags & MS_REC) {
+ strcat(buf, "rprivate,");
+ used |= MS_REC;
+ } else {
+ strcat(buf, "private,");
+ }
+ flags ^= MS_PRIVATE;
+ }
+ if (flags & MS_SLAVE) {
+ if (flags & MS_REC) {
+ strcat(buf, "rslave,");
+ used |= MS_REC;
+ } else {
+ strcat(buf, "slave,");
+ }
+ flags ^= MS_SLAVE;
+ }
+ if (flags & MS_SHARED) {
+ if (flags & MS_REC) {
+ strcat(buf, "rshared,");
+ used |= MS_REC;
+ } else {
+ strcat(buf, "shared,");
+ }
+ flags ^= MS_SHARED;
+ }
+ flags ^= used; // this is just for MS_REC
+ F(MS_RELATIME, relatime);
+ F(MS_KERNMOUNT, kernmount);
+ F(MS_I_VERSION, iversion);
+ F(MS_STRICTATIME, strictatime);
+ F(MS_LAZYTIME, lazytime);
+#ifndef MS_NOSEC
+#define MS_NOSEC (1 << 28)
+#endif
+ F(MS_NOSEC, nosec);
+#ifndef MS_BORN
+#define MS_BORN (1 << 29)
+#endif
+ F(MS_BORN, born);
+ F(MS_ACTIVE, active);
+ F(MS_NOUSER, nouser);
+#undef F
+ // Render any flags that are unaccounted for.
+ if (flags) {
+ char of[128];
+ sprintf(of, "%#lx", flags);
+ strcat(buf, of);
+ }
+ // Chop the excess comma from the end.
+ size_t len = strlen(buf);
+ if (len > 0 && buf[len - 1] == ',') {
+ buf[len - 1] = 0;
+ }
+ return buf;
+}
View
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef SNAP_CONFINE_MOUNT_OPT_H
+#define SNAP_CONFINE_MOUNT_OPT_H
+
+/**
+ * Convert flags for mount(2) system call to a string representation.
+ *
+ * The function uses an internal static buffer that is overwritten on each
+ * request.
+ **/
+const char *sc_mount_opt2str(unsigned long flags);
+
+#endif // SNAP_CONFINE_MOUNT_OPT_H
View
@@ -28,6 +28,7 @@
#include "utils.h"
#include "cleanup-funcs.h"
#include "classic.h"
+#include "mount-opt.h"
// XXX: for smaller patch, this should be in utils.h later
#include "user-support.h"
@@ -73,51 +74,6 @@ static void sc_quirk_setup_tmpfs(const char *dirname)
};
}
-const char *mount_flags_to_string(unsigned flags)
-{
- static char buf[1000];
- strcpy(buf, "");
- if (flags & MS_BIND) {
- if (flags & MS_REC) {
- strcat(buf, "rbind,");
- } else {
- strcat(buf, "bind,");
- }
- }
- if (flags & MS_PRIVATE) {
- if (flags & MS_REC) {
- strcat(buf, "rprivate,");
- } else {
- strcat(buf, "private,");
- }
- }
- if (flags & MS_SLAVE) {
- if (flags & MS_REC) {
- strcat(buf, "rslave,");
- } else {
- strcat(buf, "slave,");
- }
- }
- if (flags & MS_SHARED) {
- if (flags & MS_REC) {
- strcat(buf, "rshared,");
- } else {
- strcat(buf, "shared,");
- }
- }
- if (flags & MS_MOVE) {
- strcat(buf, "move,");
- }
- if (flags & MS_UNBINDABLE) {
- strcat(buf, "unbindable,");
- }
- size_t len = strlen(buf);
- if (len > 0 && buf[len - 1] == ',') {
- buf[len - 1] = 0;
- }
- return buf;
-}
-
/**
* Create an empty directory and bind mount something there.
*
@@ -131,7 +87,7 @@ static void sc_quirk_mkdir_bind(const char *src_dir, const char *dest_dir,
flags |= MS_BIND;
debug("creating empty directory at %s", dest_dir);
mkpath(dest_dir);
- const char *flags_str = mount_flags_to_string(flags);
+ const char *flags_str = sc_mount_opt2str(flags);
debug("performing operation: mount %s %s -o %s", src_dir, dest_dir,
flags_str);
if (mount(src_dir, dest_dir, NULL, flags, NULL) != 0) {