From 2c6f3fc932661ad87af90f3675a9ae8c3cb9bc3f Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Mon, 24 Feb 2014 23:08:26 -0600 Subject: [PATCH] always check whether rootfs is shared MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit (this expands on Dwight's recent patch, commit c597baa8f9) After unshare(CLONE_NEWNS) and before doing any mounting, always check whether rootfs is shared. Otherwise template runs or clone scripts can bleed mount activity to the host. Signed-off-by: Serge Hallyn Acked-by: Dwight Engen Acked-by: Stéphane Graber --- src/lxc/attach.c | 7 +++++++ src/lxc/bdev.c | 9 ++++++++- src/lxc/conf.c | 40 ---------------------------------------- src/lxc/lxc_usernsexec.c | 7 +++++++ src/lxc/lxccontainer.c | 6 ++++++ src/lxc/utils.c | 40 ++++++++++++++++++++++++++++++++++++++++ src/lxc/utils.h | 2 ++ 7 files changed, 70 insertions(+), 41 deletions(-) diff --git a/src/lxc/attach.c b/src/lxc/attach.c index f12d216f5..325ce53a6 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -220,6 +220,13 @@ static int lxc_attach_remount_sys_proc(void) return -1; } + if (detect_shared_rootfs()) { + if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) { + SYSERROR("Failed to make / rslave"); + ERROR("Continuing..."); + } + } + /* assume /proc is always mounted, so remount it */ ret = umount2("/proc", MNT_DETACH); if (ret < 0) { diff --git a/src/lxc/bdev.c b/src/lxc/bdev.c index 952cfebec..18f17709d 100644 --- a/src/lxc/bdev.c +++ b/src/lxc/bdev.c @@ -302,6 +302,13 @@ static int detect_fs(struct bdev *bdev, char *type, int len) if (unshare(CLONE_NEWNS) < 0) exit(1); + if (detect_shared_rootfs()) { + if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) { + SYSERROR("Failed to make / rslave"); + ERROR("Continuing..."); + } + } + ret = mount_unknown_fs(srcdev, bdev->dest, bdev->mntopts); if (ret < 0) { ERROR("failed mounting %s onto %s to detect fstype", srcdev, bdev->dest); @@ -2418,7 +2425,7 @@ static int rsync_rootfs(struct rsync_data *data) } if (detect_shared_rootfs()) { if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) { - SYSERROR("Failed to make / rslave to run rsync"); + SYSERROR("Failed to make / rslave"); ERROR("Continuing..."); } } diff --git a/src/lxc/conf.c b/src/lxc/conf.c index c9dd7ac5a..fc39897fe 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -1426,46 +1426,6 @@ static int setup_autodev(const char *root) return 0; } -/* - * Detect whether / is mounted MS_SHARED. The only way I know of to - * check that is through /proc/self/mountinfo. - * I'm only checking for /. If the container rootfs or mount location - * is MS_SHARED, but not '/', then you're out of luck - figuring that - * out would be too much work to be worth it. - */ -#define LINELEN 4096 -int detect_shared_rootfs(void) -{ - char buf[LINELEN], *p; - FILE *f; - int i; - char *p2; - - f = fopen("/proc/self/mountinfo", "r"); - if (!f) - return 0; - while (fgets(buf, LINELEN, f)) { - for (p = buf, i=0; p && i < 4; i++) - p = index(p+1, ' '); - if (!p) - continue; - p2 = index(p+1, ' '); - if (!p2) - continue; - *p2 = '\0'; - if (strcmp(p+1, "/") == 0) { - // this is '/'. is it shared? - p = index(p2+1, ' '); - if (p && strstr(p, "shared:")) { - fclose(f); - return 1; - } - } - } - fclose(f); - return 0; -} - /* * I'll forgive you for asking whether all of this is needed :) The * answer is yes. diff --git a/src/lxc/lxc_usernsexec.c b/src/lxc/lxc_usernsexec.c index e40fa53df..f06cf5b2f 100644 --- a/src/lxc/lxc_usernsexec.c +++ b/src/lxc/lxc_usernsexec.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -111,6 +112,12 @@ static int do_child(void *vargv) perror("unshare CLONE_NEWNS"); return -1; } + if (detect_shared_rootfs()) { + if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) { + printf("Failed to make / rslave"); + return -1; + } + } execvp(argv[0], argv); perror("execvpe"); return -1; diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index 0d89d1166..04277912f 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -2502,6 +2502,12 @@ static int clone_update_rootfs(struct clone_update_data *data) bdev_put(bdev); return -1; } + if (detect_shared_rootfs()) { + if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) { + SYSERROR("Failed to make / rslave"); + ERROR("Continuing..."); + } + } if (bdev->ops->mount(bdev) < 0) { bdev_put(bdev); return -1; diff --git a/src/lxc/utils.c b/src/lxc/utils.c index 52e4c86f9..da7c3b470 100644 --- a/src/lxc/utils.c +++ b/src/lxc/utils.c @@ -1194,3 +1194,43 @@ uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval) return hval; } + +/* + * Detect whether / is mounted MS_SHARED. The only way I know of to + * check that is through /proc/self/mountinfo. + * I'm only checking for /. If the container rootfs or mount location + * is MS_SHARED, but not '/', then you're out of luck - figuring that + * out would be too much work to be worth it. + */ +#define LINELEN 4096 +int detect_shared_rootfs(void) +{ + char buf[LINELEN], *p; + FILE *f; + int i; + char *p2; + + f = fopen("/proc/self/mountinfo", "r"); + if (!f) + return 0; + while (fgets(buf, LINELEN, f)) { + for (p = buf, i=0; p && i < 4; i++) + p = index(p+1, ' '); + if (!p) + continue; + p2 = index(p+1, ' '); + if (!p2) + continue; + *p2 = '\0'; + if (strcmp(p+1, "/") == 0) { + // this is '/'. is it shared? + p = index(p2+1, ' '); + if (p && strstr(p, "shared:")) { + fclose(f); + return 1; + } + } + } + fclose(f); + return 0; +} diff --git a/src/lxc/utils.h b/src/lxc/utils.h index f6f3373e4..dcf0e3445 100644 --- a/src/lxc/utils.h +++ b/src/lxc/utils.h @@ -276,3 +276,5 @@ extern bool dir_exists(const char *path); #define FNV1A_64_INIT ((uint64_t)0xcbf29ce484222325ULL) uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval); #endif + +int detect_shared_rootfs(void); -- 2.39.5