The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxc/pull/2475
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) === Signed-off-by: Christian Brauner <[email protected]>
From 6953bcb72e0f8bad30c651de4bd85f232bedacc9 Mon Sep 17 00:00:00 2001 From: Christian Brauner <[email protected]> Date: Tue, 17 Jul 2018 11:50:11 +0200 Subject: [PATCH] conf: improve rootfs setup Signed-off-by: Christian Brauner <[email protected]> --- src/lxc/conf.c | 261 ++++++++++++++++++++++++++------------------------ src/lxc/conf.h | 13 ++- src/lxc/confile.c | 26 ++++- src/lxc/criu.c | 3 +- src/lxc/start.c | 2 +- src/lxc/storage/dir.c | 16 +++- src/lxc/utils.c | 1 + 7 files changed, 187 insertions(+), 135 deletions(-) diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 33beb43d1..5283d0300 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -1104,84 +1104,6 @@ static int lxc_create_ttys(struct lxc_handler *handler) return ret; } -static int setup_rootfs_pivot_root(const char *rootfs) -{ - int ret; - int newroot = -1, oldroot = -1; - - oldroot = open("/", O_DIRECTORY | O_RDONLY); - if (oldroot < 0) { - SYSERROR("Failed to open old root directory"); - return -1; - } - - newroot = open(rootfs, O_DIRECTORY | O_RDONLY); - if (newroot < 0) { - SYSERROR("Failed to open new root directory"); - goto on_error; - } - - /* change into new root fs */ - ret = fchdir(newroot); - if (ret < 0) { - SYSERROR("Failed to change to new rootfs \"%s\"", rootfs); - goto on_error; - } - - /* pivot_root into our new root fs */ - ret = pivot_root(".", "."); - if (ret < 0) { - SYSERROR("Failed to pivot_root()"); - goto on_error; - } - - /* At this point the old-root is mounted on top of our new-root. To - * unmounted it we must not be chdir'd into it, so escape back to - * old-root. - */ - ret = fchdir(oldroot); - if (ret < 0) { - SYSERROR("Failed to enter old root directory"); - goto on_error; - } - - /* Make oldroot rslave to make sure our umounts don't propagate to the - * host. - */ - ret = mount("", ".", "", MS_SLAVE | MS_REC, NULL); - if (ret < 0) { - SYSERROR("Failed to make oldroot rslave"); - goto on_error; - } - - ret = umount2(".", MNT_DETACH); - if (ret < 0) { - SYSERROR("Failed to detach old root directory"); - goto on_error; - } - - ret = fchdir(newroot); - if (ret < 0) { - SYSERROR("Failed to re-enter new root directory"); - goto on_error; - } - - close(oldroot); - close(newroot); - - DEBUG("pivot_root(\"%s\") successful", rootfs); - - return 0; - -on_error: - if (oldroot != -1) - close(oldroot); - if (newroot != -1) - close(newroot); - - return -1; -} - /* Just create a path for /dev under $lxcpath/$name and in rootfs If we hit an * error, log it but don't fail yet. */ @@ -1365,17 +1287,16 @@ static int lxc_fill_autodev(const struct lxc_rootfs *rootfs) return 0; } -static int lxc_setup_rootfs(struct lxc_conf *conf) +static int lxc_mount_rootfs(struct lxc_conf *conf) { int ret; struct lxc_storage *bdev; - const struct lxc_rootfs *rootfs; + const struct lxc_rootfs *rootfs = &conf->rootfs; - rootfs = &conf->rootfs; if (!rootfs->path) { ret = mount("", "/", NULL, MS_SLAVE | MS_REC, 0); if (ret < 0) { - SYSERROR("Failed to make / rslave"); + SYSERROR("Failed to remount \"/\" MS_REC | MS_SLAVE"); return -1; } @@ -1413,33 +1334,36 @@ static int lxc_setup_rootfs(struct lxc_conf *conf) return 0; } -int prepare_ramfs_root(char *root) +int lxc_chroot(const struct lxc_rootfs *rootfs) { int i, ret; char *p, *p2; char buf[LXC_LINELEN], nroot[PATH_MAX]; FILE *f; + char *root = rootfs->mount; - if (!realpath(root, nroot)) - return -1; + if (!realpath(root, nroot)) { + SYSERROR("Failed to resolve \"%s\"", root); + return -errno; + } ret = chdir("/"); if (ret < 0) - return -1; + return -errno; /* We could use here MS_MOVE, but in userns this mount is locked and * can't be moved. */ - ret = mount(root, "/", NULL, MS_REC | MS_BIND, NULL); + ret = mount(nroot, "/", NULL, MS_REC | MS_BIND, NULL); if (ret < 0) { - SYSERROR("Failed to move \"%s\" into \"/\"", root); - return -1; + SYSERROR("Failed to mount \"%s\" onto \"/\" as MS_REC | MS_BIND", nroot); + return -errno; } ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL); if (ret < 0) { - SYSERROR("Failed to make \"/\" rprivate"); - return -1; + SYSERROR("Failed to remount \"/\""); + return -errno; } /* The following code cleans up inhereted mounts which are not required @@ -1457,8 +1381,8 @@ int prepare_ramfs_root(char *root) f = fopen("./proc/self/mountinfo", "r"); if (!f) { - SYSERROR("Unable to open /proc/self/mountinfo"); - return -1; + SYSERROR("Failed to open \"/proc/self/mountinfo\""); + return -errno; } while (fgets(buf, LXC_LINELEN, f)) { @@ -1498,53 +1422,143 @@ int prepare_ramfs_root(char *root) /* It is weird, but chdir("..") moves us in a new root */ ret = chdir(".."); if (ret < 0) { - SYSERROR("Unable to change working directory"); - return -1; + SYSERROR("Failed to chdir(\"..\")"); + return -errno; } ret = chroot("."); if (ret < 0) { - SYSERROR("Unable to chroot"); - return -1; + SYSERROR("Failed to chroot(\".\")"); + return -errno; } return 0; } -static int setup_pivot_root(const struct lxc_rootfs *rootfs) +/* (The following explanation is copied verbatim from the kernel.) + * + * pivot_root Semantics: + * Moves the root file system of the current process to the directory put_old, + * makes new_root as the new root file system of the current process, and sets + * root/cwd of all processes which had them on the current root to new_root. + * + * Restrictions: + * The new_root and put_old must be directories, and must not be on the + * same file system as the current process root. The put_old must be + * underneath new_root, i.e. adding a non-zero number of /.. to the string + * pointed to by put_old must yield the same directory as new_root. No other + * file system may be mounted on put_old. After all, new_root is a mountpoint. + * + * Also, the current root cannot be on the 'rootfs' (initial ramfs) filesystem. + * See Documentation/filesystems/ramfs-rootfs-initramfs.txt for alternatives + * in this situation. + * + * Notes: + * - we don't move root/cwd if they are not at the root (reason: if something + * cared enough to change them, it's probably wrong to force them elsewhere) + * - it's okay to pick a root that isn't the root of a file system, e.g. + * /nfs/my_root where /nfs is the mount point. It must be a mountpoint, + * though, so you may need to say mount --bind /nfs/my_root /nfs/my_root + * first. + */ +static int lxc_pivot_root(const char *rootfs) { int ret; + int newroot = -1, oldroot = -1; - if (!rootfs->path) { - DEBUG("Container does not have a rootfs"); - return 0; + oldroot = open("/", O_DIRECTORY | O_RDONLY); + if (oldroot < 0) { + SYSERROR("Failed to open old root directory"); + return -errno; } - if (detect_ramfs_rootfs()) { - DEBUG("Detected that container is on ramfs"); + newroot = open(rootfs, O_DIRECTORY | O_RDONLY); + if (newroot < 0) { + SYSERROR("Failed to open new root directory"); + ret = -errno; + goto on_error; + } - ret = prepare_ramfs_root(rootfs->mount); - if (ret < 0) { - ERROR("Failed to prepare minimal ramfs root"); - return -1; - } + /* change into new root fs */ + ret = fchdir(newroot); + if (ret < 0) { + SYSERROR("Failed to change to new rootfs \"%s\"", rootfs); + ret = -errno; + goto on_error; + } - DEBUG("Prepared ramfs root for container"); - return 0; + /* pivot_root into our new root fs */ + ret = pivot_root(".", "."); + if (ret < 0) { + SYSERROR("Failed to pivot_root()"); + ret = -errno; + goto on_error; } - ret = setup_rootfs_pivot_root(rootfs->mount); + /* At this point the old-root is mounted on top of our new-root. To + * unmounted it we must not be chdir'd into it, so escape back to + * old-root. + */ + ret = fchdir(oldroot); if (ret < 0) { - ERROR("Failed to pivot_root()"); - return -1; + SYSERROR("Failed to enter old root directory"); + ret = -errno; + goto on_error; } - DEBUG("Finished pivot_root()"); - return 0; + /* Make oldroot rslave to make sure our umounts don't propagate to the + * host. + */ + ret = mount("", ".", "", MS_SLAVE | MS_REC, NULL); + if (ret < 0) { + SYSERROR("Failed to make oldroot rslave"); + ret = -errno; + goto on_error; + } + + ret = umount2(".", MNT_DETACH); + if (ret < 0) { + SYSERROR("Failed to detach old root directory"); + ret = -errno; + goto on_error; + } + + ret = fchdir(newroot); + if (ret < 0) { + SYSERROR("Failed to re-enter new root directory"); + ret = -errno; + goto on_error; + } + + ret = 0; + + TRACE("pivot_root(\"%s\") successful", rootfs); + +on_error: + if (oldroot != -1) + close(oldroot); + if (newroot != -1) + close(newroot); + + return ret; } -static const struct id_map *find_mapped_nsid_entry(struct lxc_conf *conf, unsigned id, - enum idtype idtype) +static int lxc_setup_rootfs_switch_root(const struct lxc_rootfs *rootfs) +{ + if (!rootfs->path) { + DEBUG("Container does not have a rootfs"); + return 0; + } + + if (detect_ramfs_rootfs()) + return lxc_chroot(rootfs); + + return lxc_pivot_root(rootfs->mount); +} + +static const struct id_map *find_mapped_nsid_entry(struct lxc_conf *conf, + unsigned id, + enum idtype idtype) { struct lxc_list *it; struct id_map *map; @@ -1903,7 +1917,7 @@ static void parse_propagationopt(char *opt, unsigned long *flags) } } -static int parse_propagationopts(const char *mntopts, unsigned long *pflags) +int parse_propagationopts(const char *mntopts, unsigned long *pflags) { char *p, *s; char *saveptr = NULL; @@ -3379,7 +3393,8 @@ static int lxc_execute_bind_init(struct lxc_handler *handler) /* This does the work of remounting / if it is shared, calling the container * pre-mount hooks, and mounting the rootfs. */ -int do_rootfs_setup(struct lxc_conf *conf, const char *name, const char *lxcpath) +int lxc_setup_rootfs_prepare_root(struct lxc_conf *conf, const char *name, + const char *lxcpath) { int ret; @@ -3392,7 +3407,7 @@ int do_rootfs_setup(struct lxc_conf *conf, const char *name, const char *lxcpath ret = mount(path, path, "rootfs", MS_BIND, NULL); if (ret < 0) { ERROR("Failed to bind mount container / onto itself"); - return -1; + return -errno; } TRACE("Bind mounted container / onto itself"); @@ -3407,7 +3422,7 @@ int do_rootfs_setup(struct lxc_conf *conf, const char *name, const char *lxcpath return -1; } - ret = lxc_setup_rootfs(conf); + ret = lxc_mount_rootfs(conf); if (ret < 0) { ERROR("Failed to setup rootfs for"); return -1; @@ -3471,7 +3486,7 @@ int lxc_setup(struct lxc_handler *handler) const char *lxcpath = handler->lxcpath, *name = handler->name; struct lxc_conf *lxc_conf = handler->conf; - ret = do_rootfs_setup(lxc_conf, name, lxcpath); + ret = lxc_setup_rootfs_prepare_root(lxc_conf, name, lxcpath); if (ret < 0) { ERROR("Failed to setup rootfs"); return -1; @@ -3610,7 +3625,7 @@ int lxc_setup(struct lxc_handler *handler) return -1; } - ret = setup_pivot_root(&lxc_conf->rootfs); + ret = lxc_setup_rootfs_switch_root(&lxc_conf->rootfs); if (ret < 0) { ERROR("Failed to pivot root into rootfs"); return -1; diff --git a/src/lxc/conf.h b/src/lxc/conf.h index f7a879c30..1c029feac 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -150,14 +150,18 @@ struct lxc_tty_info { * optionals pivot_root, rootfs mount paths * @path : the rootfs source (directory or device) * @mount : where it is mounted - * @options : mount options * @bev_type : optional backing store type + * @options : mount options + * @mountflags : the portion of @options that are flags + * @data : the porition of @options that are not flags */ struct lxc_rootfs { char *path; char *mount; - char *options; char *bdev_type; + char *options; + unsigned long mountflags; + char *data; }; /* @@ -399,8 +403,8 @@ extern int lxc_clear_environment(struct lxc_conf *c); extern int lxc_clear_limits(struct lxc_conf *c, const char *key); extern int lxc_delete_autodev(struct lxc_handler *handler); extern void lxc_clear_includes(struct lxc_conf *conf); -extern int do_rootfs_setup(struct lxc_conf *conf, const char *name, - const char *lxcpath); +extern int lxc_setup_rootfs_prepare_root(struct lxc_conf *conf, + const char *name, const char *lxcpath); extern int lxc_setup(struct lxc_handler *handler); extern int lxc_setup_parent(struct lxc_handler *handler); extern int setup_resource_limits(struct lxc_list *limits, pid_t pid); @@ -414,6 +418,7 @@ extern int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data, const char *fn_name); extern int parse_mntopts(const char *mntopts, unsigned long *mntflags, char **mntdata); +extern int parse_propagationopts(const char *mntopts, unsigned long *pflags); extern void tmp_proc_unmount(struct lxc_conf *lxc_conf); extern void remount_all_slave(void); extern void suggest_default_idmap(void); diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 5a18d11bf..61a63f5dd 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -2073,7 +2073,27 @@ static int set_config_rootfs_mount(const char *key, const char *value, static int set_config_rootfs_options(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) { - return set_config_string_item(&lxc_conf->rootfs.options, value); + int ret; + unsigned long pflags = 0; + struct lxc_rootfs *rootfs = &lxc_conf->rootfs; + + ret = set_config_string_item(&rootfs->options, value); + if (ret < 0) + return -EINVAL; + + ret = parse_mntopts(value, &rootfs->mountflags, &rootfs->data); + if (ret < 0) + return -EINVAL; + + ret = parse_propagationopts(value, &pflags); + if (ret < 0) { + free(rootfs->data); + return -EINVAL; + } + + rootfs->mountflags |= pflags; + + return 0; } static int set_config_uts_name(const char *key, const char *value, @@ -3856,6 +3876,10 @@ static inline int clr_config_rootfs_options(const char *key, struct lxc_conf *c, { free(c->rootfs.options); c->rootfs.options = NULL; + + free(c->rootfs.data); + c->rootfs.data = NULL; + return 0; } diff --git a/src/lxc/criu.c b/src/lxc/criu.c index c36421627..0feaeac07 100644 --- a/src/lxc/criu.c +++ b/src/lxc/criu.c @@ -1015,7 +1015,8 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_ rootfs = &c->lxc_conf->rootfs; if (rootfs_is_blockdev(c->lxc_conf)) { - if (do_rootfs_setup(c->lxc_conf, c->name, c->config_path) < 0) + if (lxc_setup_rootfs_prepare_root(c->lxc_conf, c->name, + c->config_path) < 0) goto out_fini_handler; } else { if (mkdir(rootfs->mount, 0755) < 0 && errno != EEXIST) diff --git a/src/lxc/start.c b/src/lxc/start.c index 180a37ab4..65a5e1eba 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -1882,7 +1882,7 @@ int __lxc_start(const char *name, struct lxc_handler *handler, INFO("Unshared CLONE_NEWNS"); remount_all_slave(); - ret = do_rootfs_setup(conf, name, lxcpath); + ret = lxc_setup_rootfs_prepare_root(conf, name, lxcpath); if (ret < 0) { ERROR("Error setting up rootfs mount as root before spawn"); goto out_fini_nonet; diff --git a/src/lxc/storage/dir.c b/src/lxc/storage/dir.c index bfd3827de..2414f533e 100644 --- a/src/lxc/storage/dir.c +++ b/src/lxc/storage/dir.c @@ -157,7 +157,7 @@ bool dir_detect(const char *path) int dir_mount(struct lxc_storage *bdev) { int ret; - unsigned long mflags, mntflags; + unsigned long mflags = 0, mntflags = 0, pflags = 0; char *mntdata; const char *src; @@ -171,17 +171,23 @@ int dir_mount(struct lxc_storage *bdev) if (ret < 0) { ERROR("Failed to parse mount options \"%s\"", bdev->mntopts); free(mntdata); - return -22; + return -EINVAL; + } + + ret = parse_propagationopts(bdev->mntopts, &pflags); + if (ret < 0) { + ERROR("Failed to parse propagation options \"%s\"", bdev->mntopts); + free(mntdata); + return -EINVAL; } src = lxc_storage_get_path(bdev->src, bdev->type); - ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, - mntdata); + ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags | pflags, mntdata); if ((0 == ret) && (mntflags & MS_RDONLY)) { DEBUG("Remounting \"%s\" on \"%s\" readonly", src ? src : "(none)", bdev->dest ? bdev->dest : "(none)"); - mflags = add_required_remount_flags(src, bdev->dest, MS_BIND | MS_REC | mntflags | MS_REMOUNT); + mflags = add_required_remount_flags(src, bdev->dest, MS_BIND | MS_REC | mntflags | pflags | MS_REMOUNT); ret = mount(src, bdev->dest, "bind", mflags, mntdata); } diff --git a/src/lxc/utils.c b/src/lxc/utils.c index 6bb05df00..af18791a0 100644 --- a/src/lxc/utils.c +++ b/src/lxc/utils.c @@ -1324,6 +1324,7 @@ bool detect_ramfs_rootfs(void) if (p && strncmp(p, "- rootfs rootfs ", 16) == 0) { free(line); fclose(f); + INFO("Rootfs is located on ramfs"); return true; } }
_______________________________________________ lxc-devel mailing list [email protected] http://lists.linuxcontainers.org/listinfo/lxc-devel
