diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2012-07-31 16:13:04 -0400 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2012-11-19 08:59:20 -0500 |
commit | 7a472ef4be8387bc05a42e16309b02c8ca943a40 (patch) | |
tree | d08fef7f89da670c24116805dbe1bcf60e094497 /fs/namespace.c | |
parent | 771b1371686e0a63e938ada28de020b9a0040f55 (diff) |
vfs: Only support slave subtrees across different user namespaces
Sharing mount subtress with mount namespaces created by unprivileged
users allows unprivileged mounts created by unprivileged users to
propagate to mount namespaces controlled by privileged users.
Prevent nasty consequences by changing shared subtrees to slave
subtress when an unprivileged users creates a new mount namespace.
Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 11 |
1 files changed, 8 insertions, 3 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 207c7ba84ad3..4dfcaf05d17c 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -786,7 +786,7 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, | |||
786 | if (!mnt) | 786 | if (!mnt) |
787 | return ERR_PTR(-ENOMEM); | 787 | return ERR_PTR(-ENOMEM); |
788 | 788 | ||
789 | if (flag & (CL_SLAVE | CL_PRIVATE)) | 789 | if (flag & (CL_SLAVE | CL_PRIVATE | CL_SHARED_TO_SLAVE)) |
790 | mnt->mnt_group_id = 0; /* not a peer of original */ | 790 | mnt->mnt_group_id = 0; /* not a peer of original */ |
791 | else | 791 | else |
792 | mnt->mnt_group_id = old->mnt_group_id; | 792 | mnt->mnt_group_id = old->mnt_group_id; |
@@ -807,7 +807,8 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, | |||
807 | list_add_tail(&mnt->mnt_instance, &sb->s_mounts); | 807 | list_add_tail(&mnt->mnt_instance, &sb->s_mounts); |
808 | br_write_unlock(&vfsmount_lock); | 808 | br_write_unlock(&vfsmount_lock); |
809 | 809 | ||
810 | if (flag & CL_SLAVE) { | 810 | if ((flag & CL_SLAVE) || |
811 | ((flag & CL_SHARED_TO_SLAVE) && IS_MNT_SHARED(old))) { | ||
811 | list_add(&mnt->mnt_slave, &old->mnt_slave_list); | 812 | list_add(&mnt->mnt_slave, &old->mnt_slave_list); |
812 | mnt->mnt_master = old; | 813 | mnt->mnt_master = old; |
813 | CLEAR_MNT_SHARED(mnt); | 814 | CLEAR_MNT_SHARED(mnt); |
@@ -2331,6 +2332,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
2331 | struct mount *p, *q; | 2332 | struct mount *p, *q; |
2332 | struct mount *old = mnt_ns->root; | 2333 | struct mount *old = mnt_ns->root; |
2333 | struct mount *new; | 2334 | struct mount *new; |
2335 | int copy_flags; | ||
2334 | 2336 | ||
2335 | new_ns = alloc_mnt_ns(user_ns); | 2337 | new_ns = alloc_mnt_ns(user_ns); |
2336 | if (IS_ERR(new_ns)) | 2338 | if (IS_ERR(new_ns)) |
@@ -2338,7 +2340,10 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
2338 | 2340 | ||
2339 | down_write(&namespace_sem); | 2341 | down_write(&namespace_sem); |
2340 | /* First pass: copy the tree topology */ | 2342 | /* First pass: copy the tree topology */ |
2341 | new = copy_tree(old, old->mnt.mnt_root, CL_COPY_ALL | CL_EXPIRE); | 2343 | copy_flags = CL_COPY_ALL | CL_EXPIRE; |
2344 | if (user_ns != mnt_ns->user_ns) | ||
2345 | copy_flags |= CL_SHARED_TO_SLAVE; | ||
2346 | new = copy_tree(old, old->mnt.mnt_root, copy_flags); | ||
2342 | if (IS_ERR(new)) { | 2347 | if (IS_ERR(new)) { |
2343 | up_write(&namespace_sem); | 2348 | up_write(&namespace_sem); |
2344 | free_mnt_ns(new_ns); | 2349 | free_mnt_ns(new_ns); |