always check whether rootfs is shared

(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 <serge.hallyn@ubuntu.com>
Acked-by: Dwight Engen <dwight.engen@oracle.com>
Acked-by: Stéphane Graber <stgraber@ubuntu.com>
This commit is contained in:
Serge Hallyn 2014-02-24 23:08:26 -06:00 committed by Stéphane Graber
parent c2b9bd9e81
commit 2c6f3fc932
7 changed files with 70 additions and 41 deletions

View File

@ -220,6 +220,13 @@ static int lxc_attach_remount_sys_proc(void)
return -1; 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 */ /* assume /proc is always mounted, so remount it */
ret = umount2("/proc", MNT_DETACH); ret = umount2("/proc", MNT_DETACH);
if (ret < 0) { if (ret < 0) {

View File

@ -302,6 +302,13 @@ static int detect_fs(struct bdev *bdev, char *type, int len)
if (unshare(CLONE_NEWNS) < 0) if (unshare(CLONE_NEWNS) < 0)
exit(1); 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); ret = mount_unknown_fs(srcdev, bdev->dest, bdev->mntopts);
if (ret < 0) { if (ret < 0) {
ERROR("failed mounting %s onto %s to detect fstype", srcdev, bdev->dest); 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 (detect_shared_rootfs()) {
if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) { if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) {
SYSERROR("Failed to make / rslave to run rsync"); SYSERROR("Failed to make / rslave");
ERROR("Continuing..."); ERROR("Continuing...");
} }
} }

View File

@ -1426,46 +1426,6 @@ static int setup_autodev(const char *root)
return 0; 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 * I'll forgive you for asking whether all of this is needed :) The
* answer is yes. * answer is yes.

View File

@ -35,6 +35,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/mount.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sched.h> #include <sched.h>
#include <pwd.h> #include <pwd.h>
@ -111,6 +112,12 @@ static int do_child(void *vargv)
perror("unshare CLONE_NEWNS"); perror("unshare CLONE_NEWNS");
return -1; 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); execvp(argv[0], argv);
perror("execvpe"); perror("execvpe");
return -1; return -1;

View File

@ -2502,6 +2502,12 @@ static int clone_update_rootfs(struct clone_update_data *data)
bdev_put(bdev); bdev_put(bdev);
return -1; 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) { if (bdev->ops->mount(bdev) < 0) {
bdev_put(bdev); bdev_put(bdev);
return -1; return -1;

View File

@ -1194,3 +1194,43 @@ uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval)
return 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;
}

View File

@ -276,3 +276,5 @@ extern bool dir_exists(const char *path);
#define FNV1A_64_INIT ((uint64_t)0xcbf29ce484222325ULL) #define FNV1A_64_INIT ((uint64_t)0xcbf29ce484222325ULL)
uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval); uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval);
#endif #endif
int detect_shared_rootfs(void);