vfs: Only support slave subtrees across different user namespaces
authorEric W. Biederman <ebiederm@xmission.com>
Tue, 31 Jul 2012 20:13:04 +0000 (13:13 -0700)
committerEric W. Biederman <ebiederm@xmission.com>
Mon, 19 Nov 2012 13:59:20 +0000 (05:59 -0800)
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>
fs/namespace.c
fs/pnode.h

index 207c7ba84ad3976ea2048366a9eccd5f6c12a785..4dfcaf05d17c67916169a52f54acf33aa4f04cd6 100644 (file)
@@ -786,7 +786,7 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
        if (!mnt)
                return ERR_PTR(-ENOMEM);
 
-       if (flag & (CL_SLAVE | CL_PRIVATE))
+       if (flag & (CL_SLAVE | CL_PRIVATE | CL_SHARED_TO_SLAVE))
                mnt->mnt_group_id = 0; /* not a peer of original */
        else
                mnt->mnt_group_id = old->mnt_group_id;
@@ -807,7 +807,8 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
        list_add_tail(&mnt->mnt_instance, &sb->s_mounts);
        br_write_unlock(&vfsmount_lock);
 
-       if (flag & CL_SLAVE) {
+       if ((flag & CL_SLAVE) ||
+           ((flag & CL_SHARED_TO_SLAVE) && IS_MNT_SHARED(old))) {
                list_add(&mnt->mnt_slave, &old->mnt_slave_list);
                mnt->mnt_master = old;
                CLEAR_MNT_SHARED(mnt);
@@ -2331,6 +2332,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
        struct mount *p, *q;
        struct mount *old = mnt_ns->root;
        struct mount *new;
+       int copy_flags;
 
        new_ns = alloc_mnt_ns(user_ns);
        if (IS_ERR(new_ns))
@@ -2338,7 +2340,10 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
 
        down_write(&namespace_sem);
        /* First pass: copy the tree topology */
-       new = copy_tree(old, old->mnt.mnt_root, CL_COPY_ALL | CL_EXPIRE);
+       copy_flags = CL_COPY_ALL | CL_EXPIRE;
+       if (user_ns != mnt_ns->user_ns)
+               copy_flags |= CL_SHARED_TO_SLAVE;
+       new = copy_tree(old, old->mnt.mnt_root, copy_flags);
        if (IS_ERR(new)) {
                up_write(&namespace_sem);
                free_mnt_ns(new_ns);
index 65c60979d5410f9b3aae1248e9503683c2397358..19b853a3445cb907665b4403484984a0c525af68 100644 (file)
@@ -22,6 +22,7 @@
 #define CL_COPY_ALL            0x04
 #define CL_MAKE_SHARED                 0x08
 #define CL_PRIVATE             0x10
+#define CL_SHARED_TO_SLAVE     0x20
 
 static inline void set_mnt_shared(struct mount *mnt)
 {