Unverified Commit 01fc55d5 by Stéphane Graber Committed by GitHub

Merge pull request #2475 from brauner/2018-07-16/monitor_signal_pdeath

conf: improve rootfs setup
parents e6b4213b dccffc82
...@@ -1140,84 +1140,6 @@ on_error: ...@@ -1140,84 +1140,6 @@ on_error:
return ret; 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 /* Just create a path for /dev under $lxcpath/$name and in rootfs If we hit an
* error, log it but don't fail yet. * error, log it but don't fail yet.
*/ */
...@@ -1401,17 +1323,16 @@ static int lxc_fill_autodev(const struct lxc_rootfs *rootfs) ...@@ -1401,17 +1323,16 @@ static int lxc_fill_autodev(const struct lxc_rootfs *rootfs)
return 0; return 0;
} }
static int lxc_setup_rootfs(struct lxc_conf *conf) static int lxc_mount_rootfs(struct lxc_conf *conf)
{ {
int ret; int ret;
struct lxc_storage *bdev; struct lxc_storage *bdev;
const struct lxc_rootfs *rootfs; const struct lxc_rootfs *rootfs = &conf->rootfs;
rootfs = &conf->rootfs;
if (!rootfs->path) { if (!rootfs->path) {
ret = mount("", "/", NULL, MS_SLAVE | MS_REC, 0); ret = mount("", "/", NULL, MS_SLAVE | MS_REC, 0);
if (ret < 0) { if (ret < 0) {
SYSERROR("Failed to make / rslave"); SYSERROR("Failed to remount \"/\" MS_REC | MS_SLAVE");
return -1; return -1;
} }
...@@ -1449,15 +1370,18 @@ static int lxc_setup_rootfs(struct lxc_conf *conf) ...@@ -1449,15 +1370,18 @@ static int lxc_setup_rootfs(struct lxc_conf *conf)
return 0; return 0;
} }
int prepare_ramfs_root(char *root) int lxc_chroot(const struct lxc_rootfs *rootfs)
{ {
int i, ret; int i, ret;
char *p, *p2; char *p, *p2;
char buf[LXC_LINELEN], nroot[PATH_MAX]; char buf[LXC_LINELEN], nroot[PATH_MAX];
FILE *f; FILE *f;
char *root = rootfs->mount;
if (!realpath(root, nroot)) if (!realpath(root, nroot)) {
SYSERROR("Failed to resolve \"%s\"", root);
return -1; return -1;
}
ret = chdir("/"); ret = chdir("/");
if (ret < 0) if (ret < 0)
...@@ -1466,15 +1390,15 @@ int prepare_ramfs_root(char *root) ...@@ -1466,15 +1390,15 @@ int prepare_ramfs_root(char *root)
/* We could use here MS_MOVE, but in userns this mount is locked and /* We could use here MS_MOVE, but in userns this mount is locked and
* can't be moved. * 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) { if (ret < 0) {
SYSERROR("Failed to move \"%s\" into \"/\"", root); SYSERROR("Failed to mount \"%s\" onto \"/\" as MS_REC | MS_BIND", nroot);
return -1; return -1;
} }
ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL); ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL);
if (ret < 0) { if (ret < 0) {
SYSERROR("Failed to make \"/\" rprivate"); SYSERROR("Failed to remount \"/\"");
return -1; return -1;
} }
...@@ -1493,7 +1417,7 @@ int prepare_ramfs_root(char *root) ...@@ -1493,7 +1417,7 @@ int prepare_ramfs_root(char *root)
f = fopen("./proc/self/mountinfo", "r"); f = fopen("./proc/self/mountinfo", "r");
if (!f) { if (!f) {
SYSERROR("Unable to open /proc/self/mountinfo"); SYSERROR("Failed to open \"/proc/self/mountinfo\"");
return -1; return -1;
} }
...@@ -1534,53 +1458,141 @@ int prepare_ramfs_root(char *root) ...@@ -1534,53 +1458,141 @@ int prepare_ramfs_root(char *root)
/* It is weird, but chdir("..") moves us in a new root */ /* It is weird, but chdir("..") moves us in a new root */
ret = chdir(".."); ret = chdir("..");
if (ret < 0) { if (ret < 0) {
SYSERROR("Unable to change working directory"); SYSERROR("Failed to chdir(\"..\")");
return -1; return -1;
} }
ret = chroot("."); ret = chroot(".");
if (ret < 0) { if (ret < 0) {
SYSERROR("Unable to chroot"); SYSERROR("Failed to chroot(\".\")");
return -1; return -1;
} }
return 0; 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, ret = -1;
if (!rootfs->path) { oldroot = open("/", O_DIRECTORY | O_RDONLY);
DEBUG("Container does not have a rootfs"); if (oldroot < 0) {
return 0; SYSERROR("Failed to open old root directory");
return -1;
} }
if (detect_ramfs_rootfs()) { newroot = open(rootfs, O_DIRECTORY | O_RDONLY);
DEBUG("Detected that container is on ramfs"); if (newroot < 0) {
SYSERROR("Failed to open new root directory");
goto on_error;
}
ret = prepare_ramfs_root(rootfs->mount); /* change into new root fs */
if (ret < 0) { ret = fchdir(newroot);
ERROR("Failed to prepare minimal ramfs root"); if (ret < 0) {
return -1; ret = -1;
} SYSERROR("Failed to change to new rootfs \"%s\"", rootfs);
goto on_error;
}
DEBUG("Prepared ramfs root for container"); /* pivot_root into our new root fs */
return 0; ret = pivot_root(".", ".");
if (ret < 0) {
ret = -1;
SYSERROR("Failed to pivot_root()");
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) { if (ret < 0) {
ERROR("Failed to pivot_root()"); ret = -1;
return -1; SYSERROR("Failed to enter old root directory");
goto on_error;
} }
DEBUG("Finished pivot_root()"); /* Make oldroot rslave to make sure our umounts don't propagate to the
return 0; * host.
*/
ret = mount("", ".", "", MS_SLAVE | MS_REC, NULL);
if (ret < 0) {
ret = -1;
SYSERROR("Failed to make oldroot rslave");
goto on_error;
}
ret = umount2(".", MNT_DETACH);
if (ret < 0) {
ret = -1;
SYSERROR("Failed to detach old root directory");
goto on_error;
}
ret = fchdir(newroot);
if (ret < 0) {
ret = -1;
SYSERROR("Failed to re-enter new root directory");
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 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, static const struct id_map *find_mapped_nsid_entry(struct lxc_conf *conf,
enum idtype idtype) unsigned id,
enum idtype idtype)
{ {
struct lxc_list *it; struct lxc_list *it;
struct id_map *map; struct id_map *map;
...@@ -1949,7 +1961,7 @@ static void parse_propagationopt(char *opt, unsigned long *flags) ...@@ -1949,7 +1961,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 *p, *s;
...@@ -3451,7 +3463,8 @@ out: ...@@ -3451,7 +3463,8 @@ out:
/* This does the work of remounting / if it is shared, calling the container /* This does the work of remounting / if it is shared, calling the container
* pre-mount hooks, and mounting the rootfs. * 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; int ret;
...@@ -3479,7 +3492,7 @@ int do_rootfs_setup(struct lxc_conf *conf, const char *name, const char *lxcpath ...@@ -3479,7 +3492,7 @@ int do_rootfs_setup(struct lxc_conf *conf, const char *name, const char *lxcpath
return -1; return -1;
} }
ret = lxc_setup_rootfs(conf); ret = lxc_mount_rootfs(conf);
if (ret < 0) { if (ret < 0) {
ERROR("Failed to setup rootfs for"); ERROR("Failed to setup rootfs for");
return -1; return -1;
...@@ -3543,7 +3556,7 @@ int lxc_setup(struct lxc_handler *handler) ...@@ -3543,7 +3556,7 @@ int lxc_setup(struct lxc_handler *handler)
const char *lxcpath = handler->lxcpath, *name = handler->name; const char *lxcpath = handler->lxcpath, *name = handler->name;
struct lxc_conf *lxc_conf = handler->conf; 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) { if (ret < 0) {
ERROR("Failed to setup rootfs"); ERROR("Failed to setup rootfs");
return -1; return -1;
...@@ -3682,7 +3695,7 @@ int lxc_setup(struct lxc_handler *handler) ...@@ -3682,7 +3695,7 @@ int lxc_setup(struct lxc_handler *handler)
return -1; return -1;
} }
ret = setup_pivot_root(&lxc_conf->rootfs); ret = lxc_setup_rootfs_switch_root(&lxc_conf->rootfs);
if (ret < 0) { if (ret < 0) {
ERROR("Failed to pivot root into rootfs"); ERROR("Failed to pivot root into rootfs");
return -1; return -1;
......
...@@ -150,14 +150,18 @@ struct lxc_tty_info { ...@@ -150,14 +150,18 @@ struct lxc_tty_info {
* optionals pivot_root, rootfs mount paths * optionals pivot_root, rootfs mount paths
* @path : the rootfs source (directory or device) * @path : the rootfs source (directory or device)
* @mount : where it is mounted * @mount : where it is mounted
* @options : mount options
* @bev_type : optional backing store type * @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 { struct lxc_rootfs {
char *path; char *path;
char *mount; char *mount;
char *options;
char *bdev_type; char *bdev_type;
char *options;
unsigned long mountflags;
char *data;
}; };
/* /*
...@@ -413,8 +417,8 @@ extern int lxc_clear_environment(struct lxc_conf *c); ...@@ -413,8 +417,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_clear_limits(struct lxc_conf *c, const char *key);
extern int lxc_delete_autodev(struct lxc_handler *handler); extern int lxc_delete_autodev(struct lxc_handler *handler);
extern void lxc_clear_includes(struct lxc_conf *conf); extern void lxc_clear_includes(struct lxc_conf *conf);
extern int do_rootfs_setup(struct lxc_conf *conf, const char *name, extern int lxc_setup_rootfs_prepare_root(struct lxc_conf *conf,
const char *lxcpath); const char *name, const char *lxcpath);
extern int lxc_setup(struct lxc_handler *handler); extern int lxc_setup(struct lxc_handler *handler);
extern int lxc_setup_parent(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); extern int setup_resource_limits(struct lxc_list *limits, pid_t pid);
...@@ -428,6 +432,7 @@ extern int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), ...@@ -428,6 +432,7 @@ extern int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *),
void *data, const char *fn_name); void *data, const char *fn_name);
extern int parse_mntopts(const char *mntopts, unsigned long *mntflags, extern int parse_mntopts(const char *mntopts, unsigned long *mntflags,
char **mntdata); char **mntdata);
extern int parse_propagationopts(const char *mntopts, unsigned long *pflags);
extern void tmp_proc_unmount(struct lxc_conf *lxc_conf); extern void tmp_proc_unmount(struct lxc_conf *lxc_conf);
extern void remount_all_slave(void); extern void remount_all_slave(void);
extern void suggest_default_idmap(void); extern void suggest_default_idmap(void);
......
...@@ -2143,7 +2143,32 @@ static int set_config_rootfs_mount(const char *key, const char *value, ...@@ -2143,7 +2143,32 @@ static int set_config_rootfs_mount(const char *key, const char *value,
static int set_config_rootfs_options(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) struct lxc_conf *lxc_conf, void *data)
{ {
return set_config_string_item(&lxc_conf->rootfs.options, value); int ret;
unsigned long mflags = 0, pflags = 0;
char *mdata = NULL, *opts = NULL;
struct lxc_rootfs *rootfs = &lxc_conf->rootfs;
ret = parse_mntopts(value, &mflags, &mdata);
if (ret < 0)
return -EINVAL;
ret = parse_propagationopts(value, &pflags);
if (ret < 0) {
free(mdata);
return -EINVAL;
}
ret = set_config_string_item(&opts, value);
if (ret < 0) {
free(mdata);
return -ENOMEM;
}
rootfs->mountflags = mflags | pflags;
rootfs->options = opts;
rootfs->data = mdata;
return 0;
} }
static int set_config_uts_name(const char *key, const char *value, static int set_config_uts_name(const char *key, const char *value,
...@@ -3964,6 +3989,10 @@ static inline int clr_config_rootfs_options(const char *key, struct lxc_conf *c, ...@@ -3964,6 +3989,10 @@ static inline int clr_config_rootfs_options(const char *key, struct lxc_conf *c,
{ {
free(c->rootfs.options); free(c->rootfs.options);
c->rootfs.options = NULL; c->rootfs.options = NULL;
free(c->rootfs.data);
c->rootfs.data = NULL;
return 0; return 0;
} }
......
...@@ -1016,7 +1016,8 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_ ...@@ -1016,7 +1016,8 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
rootfs = &c->lxc_conf->rootfs; rootfs = &c->lxc_conf->rootfs;
if (rootfs_is_blockdev(c->lxc_conf)) { 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; goto out_fini_handler;
} else { } else {
if (mkdir(rootfs->mount, 0755) < 0 && errno != EEXIST) if (mkdir(rootfs->mount, 0755) < 0 && errno != EEXIST)
......
...@@ -1995,7 +1995,7 @@ int __lxc_start(const char *name, struct lxc_handler *handler, ...@@ -1995,7 +1995,7 @@ int __lxc_start(const char *name, struct lxc_handler *handler,
INFO("Unshared CLONE_NEWNS"); INFO("Unshared CLONE_NEWNS");
remount_all_slave(); remount_all_slave();
ret = do_rootfs_setup(conf, name, lxcpath); ret = lxc_setup_rootfs_prepare_root(conf, name, lxcpath);
if (ret < 0) { if (ret < 0) {
ERROR("Error setting up rootfs mount as root before spawn"); ERROR("Error setting up rootfs mount as root before spawn");
goto out_fini_nonet; goto out_fini_nonet;
......
...@@ -157,7 +157,7 @@ bool dir_detect(const char *path) ...@@ -157,7 +157,7 @@ bool dir_detect(const char *path)
int dir_mount(struct lxc_storage *bdev) int dir_mount(struct lxc_storage *bdev)
{ {
int ret; int ret;
unsigned long mflags, mntflags; unsigned long mflags = 0, mntflags = 0, pflags = 0;
char *mntdata; char *mntdata;
const char *src; const char *src;
...@@ -171,17 +171,23 @@ int dir_mount(struct lxc_storage *bdev) ...@@ -171,17 +171,23 @@ int dir_mount(struct lxc_storage *bdev)
if (ret < 0) { if (ret < 0) {
ERROR("Failed to parse mount options \"%s\"", bdev->mntopts); ERROR("Failed to parse mount options \"%s\"", bdev->mntopts);
free(mntdata); 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); src = lxc_storage_get_path(bdev->src, bdev->type);
ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags | pflags, mntdata);
mntdata);
if ((0 == ret) && (mntflags & MS_RDONLY)) { if ((0 == ret) && (mntflags & MS_RDONLY)) {
DEBUG("Remounting \"%s\" on \"%s\" readonly", DEBUG("Remounting \"%s\" on \"%s\" readonly",
src ? src : "(none)", bdev->dest ? bdev->dest : "(none)"); 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); ret = mount(src, bdev->dest, "bind", mflags, mntdata);
} }
......
...@@ -1330,6 +1330,7 @@ bool detect_ramfs_rootfs(void) ...@@ -1330,6 +1330,7 @@ bool detect_ramfs_rootfs(void)
if (p && strncmp(p, "- rootfs rootfs ", 16) == 0) { if (p && strncmp(p, "- rootfs rootfs ", 16) == 0) {
free(line); free(line);
fclose(f); fclose(f);
INFO("Rootfs is located on ramfs");
return true; return true;
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment