From 5f0a6347acf0da462cd5ac6d913ffa28e7463ef5 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 6 Dec 2019 22:45:14 +0100 Subject: [PATCH] nspawn: Enable specifying root as the mount target directory. Fixes #3847. --- src/nspawn/nspawn-mount.c | 17 ++++++++--------- src/nspawn/nspawn-mount.h | 4 +++- src/nspawn/nspawn.c | 23 ++++++++++++++++++++--- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index 6407503c4c..8225cf473a 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -222,8 +222,6 @@ int bind_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_only) if (!path_is_absolute(destination)) return -EINVAL; - if (empty_or_root(destination)) - return -EINVAL; m = custom_mount_add(l, n, CUSTOM_MOUNT_BIND); if (!m) @@ -262,8 +260,6 @@ int tmpfs_mount_parse(CustomMount **l, size_t *n, const char *s) { if (!path_is_absolute(path)) return -EINVAL; - if (empty_or_root(path)) - return -EINVAL; m = custom_mount_add(l, n, CUSTOM_MOUNT_TMPFS); if (!m) @@ -323,9 +319,6 @@ int overlay_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_onl return -EINVAL; } - if (empty_or_root(destination)) - return -EINVAL; - m = custom_mount_add(l, n, CUSTOM_MOUNT_OVERLAY); if (!m) return -ENOMEM; @@ -923,7 +916,7 @@ int mount_custom( CustomMount *mounts, size_t n, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context, - bool in_userns) { + MountSettingsMask mount_settings) { size_t i; int r; @@ -933,7 +926,13 @@ int mount_custom( for (i = 0; i < n; i++) { CustomMount *m = mounts + i; - if (m->in_userns != in_userns) + if ((mount_settings & MOUNT_IN_USERNS) != m->in_userns) + continue; + + if (mount_settings & MOUNT_ROOT_ONLY && !path_equal(m->destination, "/")) + continue; + + if (mount_settings & MOUNT_NON_ROOT_ONLY && path_equal(m->destination, "/")) continue; switch (m->type) { diff --git a/src/nspawn/nspawn-mount.h b/src/nspawn/nspawn-mount.h index ff6990c734..08d3e68f29 100644 --- a/src/nspawn/nspawn-mount.h +++ b/src/nspawn/nspawn-mount.h @@ -14,6 +14,8 @@ typedef enum MountSettingsMask { MOUNT_APPLY_APIVFS_NETNS = 1 << 4, /* if set, /proc/sys/net will be mounted read-write. Works only if MOUNT_APPLY_APIVFS_RO is also set. */ MOUNT_APPLY_TMPFS_TMP = 1 << 5, /* if set, /tmp will be mounted as tmpfs */ + MOUNT_ROOT_ONLY = 1 << 6, /* if set, only root mounts are mounted */ + MOUNT_NON_ROOT_ONLY = 1 << 7, /* if set, only non-root mounts are mounted */ } MountSettingsMask; typedef enum CustomMountType { @@ -52,7 +54,7 @@ int inaccessible_mount_parse(CustomMount **l, size_t *n, const char *s); int mount_all(const char *dest, MountSettingsMask mount_settings, uid_t uid_shift, const char *selinux_apifs_context); int mount_sysfs(const char *dest, MountSettingsMask mount_settings); -int mount_custom(const char *dest, CustomMount *mounts, size_t n, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context, bool in_userns); +int mount_custom(const char *dest, CustomMount *mounts, size_t n, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context, MountSettingsMask mount_settings); int setup_volatile_mode(const char *directory, VolatileMode mode, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 9fac326219..31a9a6d11f 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -2979,7 +2979,7 @@ static int inner_child( 0, 0, arg_selinux_apifs_context, - true); + MOUNT_NON_ROOT_ONLY | MOUNT_IN_USERNS); if (r < 0) return r; @@ -3371,6 +3371,18 @@ static int outer_child( if (r < 0) return r; + r = mount_custom( + directory, + arg_custom_mounts, + arg_n_custom_mounts, + arg_userns_mode != USER_NAMESPACE_NO, + arg_uid_shift, + arg_uid_range, + arg_selinux_apifs_context, + MOUNT_ROOT_ONLY); + if (r < 0) + return r; + if (dissected_image) { /* Now we know the uid shift, let's now mount everything else that might be in the image. */ r = dissected_image_mount(dissected_image, directory, arg_uid_shift, @@ -3401,7 +3413,12 @@ static int outer_child( * inside the container that create a new mount namespace. * See https://github.com/systemd/systemd/issues/3860 * Further submounts (such as /dev) done after this will inherit the - * shared propagation mode. */ + * shared propagation mode. + * + * IMPORTANT: Do not overmount the root directory anymore from now on to + * enable moving the root directory mount to root later on. + * https://github.com/systemd/systemd/issues/3847#issuecomment-562735251 + */ r = mount_verbose(LOG_ERR, NULL, directory, NULL, MS_SHARED|MS_REC, NULL); if (r < 0) return r; @@ -3474,7 +3491,7 @@ static int outer_child( arg_uid_shift, arg_uid_range, arg_selinux_apifs_context, - false); + MOUNT_NON_ROOT_ONLY); if (r < 0) return r;