]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: open /proc/self/mountinfo early to allow mounts over /proc (#5985)
authorTimothée Ravier <tim@siosm.fr>
Fri, 19 May 2017 12:38:40 +0000 (14:38 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 19 May 2017 12:38:40 +0000 (14:38 +0200)
Enable masking the /proc folder using the 'InaccessiblePaths' unit
option.

This also slightly simplify mounts setup as the bind_remount_recursive
function will only open /proc/self/mountinfo once.

This is based on the suggestion at:
https://lists.freedesktop.org/archives/systemd-devel/2017-April/038634.html

src/basic/mount-util.c
src/basic/mount-util.h
src/core/namespace.c

index a8fd63fb45807ddc582227ab341a57f380ecee0b..7b9400b47cad450c347e0fb4c6ab0d58c287ea8d 100644 (file)
@@ -317,11 +317,16 @@ static int get_mount_flags(const char *path, unsigned long *flags) {
         return 0;
 }
 
-int bind_remount_recursive(const char *prefix, bool ro, char **blacklist) {
+/* Use this function only if do you have direct access to /proc/self/mountinfo
+ * and need the caller to open it for you. This is the case when /proc is
+ * masked or not mounted. Otherwise, use bind_remount_recursive. */
+int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **blacklist, FILE *proc_self_mountinfo) {
         _cleanup_set_free_free_ Set *done = NULL;
         _cleanup_free_ char *cleaned = NULL;
         int r;
 
+        assert(proc_self_mountinfo);
+
         /* Recursively remount a directory (and all its submounts) read-only or read-write. If the directory is already
          * mounted, we reuse the mount and simply mark it MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write
          * operation). If it isn't we first make it one. Afterwards we apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to
@@ -344,7 +349,6 @@ int bind_remount_recursive(const char *prefix, bool ro, char **blacklist) {
                 return -ENOMEM;
 
         for (;;) {
-                _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
                 _cleanup_set_free_free_ Set *todo = NULL;
                 bool top_autofs = false;
                 char *x;
@@ -354,9 +358,7 @@ int bind_remount_recursive(const char *prefix, bool ro, char **blacklist) {
                 if (!todo)
                         return -ENOMEM;
 
-                proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
-                if (!proc_self_mountinfo)
-                        return -errno;
+                rewind(proc_self_mountinfo);
 
                 for (;;) {
                         _cleanup_free_ char *path = NULL, *p = NULL, *type = NULL;
@@ -495,6 +497,16 @@ int bind_remount_recursive(const char *prefix, bool ro, char **blacklist) {
         }
 }
 
+int bind_remount_recursive(const char *prefix, bool ro, char **blacklist) {
+        _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
+
+        proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
+        if (!proc_self_mountinfo)
+                return -errno;
+
+        return bind_remount_recursive_with_mountinfo(prefix, ro, blacklist, proc_self_mountinfo);
+}
+
 int mount_move_root(const char *path) {
         assert(path);
 
index 1615c94e9abe73c3cd4a65055df1cba2a586fafd..2e24a184c5351fed13408eac725243a4893be365 100644 (file)
@@ -36,6 +36,7 @@ int repeat_unmount(const char *path, int flags);
 
 int umount_recursive(const char *target, int flags);
 int bind_remount_recursive(const char *prefix, bool ro, char **blacklist);
+int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **blacklist, FILE *proc_self_mountinfo);
 
 int mount_move_root(const char *path);
 
index 8235a64406e166aabdb68bbc082021e770cbf60c..05175e9552b11c59e95b02bb99d17071d1bc0b52 100644 (file)
@@ -793,13 +793,14 @@ static int apply_mount(
         return 0;
 }
 
-static int make_read_only(MountEntry *m, char **blacklist) {
+static int make_read_only(MountEntry *m, char **blacklist, FILE *proc_self_mountinfo) {
         int r = 0;
 
         assert(m);
+        assert(proc_self_mountinfo);
 
         if (mount_entry_read_only(m))
-                r = bind_remount_recursive(mount_entry_path(m), true, blacklist);
+                r = bind_remount_recursive_with_mountinfo(mount_entry_path(m), true, blacklist, proc_self_mountinfo);
         else if (m->mode == PRIVATE_DEV) { /* Superblock can be readonly but the submounts can't */
                 if (mount(NULL, mount_entry_path(m), NULL, MS_REMOUNT|DEV_MOUNT_OPTIONS|MS_RDONLY, NULL) < 0)
                         r = -errno;
@@ -1082,9 +1083,18 @@ int setup_namespace(
         }
 
         if (n_mounts > 0) {
+                _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
                 char **blacklist;
                 unsigned j;
 
+                /* Open /proc/self/mountinfo now as it may become unavailable if we mount anything on top of /proc.
+                 * For example, this is the case with the option: 'InaccessiblePaths=/proc' */
+                proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
+                if (!proc_self_mountinfo) {
+                        r = -errno;
+                        goto finish;
+                }
+
                 /* First round, add in all special mounts we need */
                 for (m = mounts; m < mounts + n_mounts; ++m) {
                         r = apply_mount(root_directory, m, tmp_dir, var_tmp_dir);
@@ -1100,7 +1110,7 @@ int setup_namespace(
 
                 /* Second round, flip the ro bits if necessary. */
                 for (m = mounts; m < mounts + n_mounts; ++m) {
-                        r = make_read_only(m, blacklist);
+                        r = make_read_only(m, blacklist, proc_self_mountinfo);
                         if (r < 0)
                                 goto finish;
                 }