From: Timothée Ravier Date: Fri, 19 May 2017 12:38:40 +0000 (+0200) Subject: core: open /proc/self/mountinfo early to allow mounts over /proc (#5985) X-Git-Tag: v234~189 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ac9de0b3794aed5010d050791dff3b7748918fec;p=thirdparty%2Fsystemd.git core: open /proc/self/mountinfo early to allow mounts over /proc (#5985) 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 --- diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index a8fd63fb458..7b9400b47ca 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -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); diff --git a/src/basic/mount-util.h b/src/basic/mount-util.h index 1615c94e9ab..2e24a184c53 100644 --- a/src/basic/mount-util.h +++ b/src/basic/mount-util.h @@ -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); diff --git a/src/core/namespace.c b/src/core/namespace.c index 8235a64406e..05175e9552b 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -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; }