vfs: Add a user namespace reference from struct mnt_namespace
authorEric W. Biederman <ebiederm@xmission.com>
Fri, 27 Jul 2012 04:08:32 +0000 (21:08 -0700)
committerEric W. Biederman <ebiederm@xmission.com>
Mon, 19 Nov 2012 13:59:19 +0000 (05:59 -0800)
This will allow for support for unprivileged mounts in a new user namespace.

Acked-by: "Serge E. Hallyn" <serge@hallyn.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
fs/mount.h
fs/namespace.c
include/linux/mnt_namespace.h
kernel/nsproxy.c

index e9c37dd..630fafc 100644 (file)
@@ -6,6 +6,7 @@ struct mnt_namespace {
        atomic_t                count;
        struct mount *  root;
        struct list_head        list;
+       struct user_namespace   *user_ns;
        u64                     seq;    /* Sequence number to prevent loops */
        wait_queue_head_t poll;
        int event;
index d287e7e..207c7ba 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/export.h>
 #include <linux/capability.h>
 #include <linux/mnt_namespace.h>
+#include <linux/user_namespace.h>
 #include <linux/namei.h>
 #include <linux/security.h>
 #include <linux/idr.h>
@@ -2286,6 +2287,12 @@ dput_out:
        return retval;
 }
 
+static void free_mnt_ns(struct mnt_namespace *ns)
+{
+       put_user_ns(ns->user_ns);
+       kfree(ns);
+}
+
 /*
  * Assign a sequence number so we can detect when we attempt to bind
  * mount a reference to an older mount namespace into the current
@@ -2295,7 +2302,7 @@ dput_out:
  */
 static atomic64_t mnt_ns_seq = ATOMIC64_INIT(1);
 
-static struct mnt_namespace *alloc_mnt_ns(void)
+static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns)
 {
        struct mnt_namespace *new_ns;
 
@@ -2308,6 +2315,7 @@ static struct mnt_namespace *alloc_mnt_ns(void)
        INIT_LIST_HEAD(&new_ns->list);
        init_waitqueue_head(&new_ns->poll);
        new_ns->event = 0;
+       new_ns->user_ns = get_user_ns(user_ns);
        return new_ns;
 }
 
@@ -2316,7 +2324,7 @@ static struct mnt_namespace *alloc_mnt_ns(void)
  * copied from the namespace of the passed in task structure.
  */
 static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
-               struct fs_struct *fs)
+               struct user_namespace *user_ns, struct fs_struct *fs)
 {
        struct mnt_namespace *new_ns;
        struct vfsmount *rootmnt = NULL, *pwdmnt = NULL;
@@ -2324,7 +2332,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
        struct mount *old = mnt_ns->root;
        struct mount *new;
 
-       new_ns = alloc_mnt_ns();
+       new_ns = alloc_mnt_ns(user_ns);
        if (IS_ERR(new_ns))
                return new_ns;
 
@@ -2333,7 +2341,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
        new = copy_tree(old, old->mnt.mnt_root, CL_COPY_ALL | CL_EXPIRE);
        if (IS_ERR(new)) {
                up_write(&namespace_sem);
-               kfree(new_ns);
+               free_mnt_ns(new_ns);
                return ERR_CAST(new);
        }
        new_ns->root = new;
@@ -2374,7 +2382,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
 }
 
 struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
-               struct fs_struct *new_fs)
+               struct user_namespace *user_ns, struct fs_struct *new_fs)
 {
        struct mnt_namespace *new_ns;
 
@@ -2384,7 +2392,7 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
        if (!(flags & CLONE_NEWNS))
                return ns;
 
-       new_ns = dup_mnt_ns(ns, new_fs);
+       new_ns = dup_mnt_ns(ns, user_ns, new_fs);
 
        put_mnt_ns(ns);
        return new_ns;
@@ -2396,7 +2404,7 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
  */
 static struct mnt_namespace *create_mnt_ns(struct vfsmount *m)
 {
-       struct mnt_namespace *new_ns = alloc_mnt_ns();
+       struct mnt_namespace *new_ns = alloc_mnt_ns(&init_user_ns);
        if (!IS_ERR(new_ns)) {
                struct mount *mnt = real_mount(m);
                mnt->mnt_ns = new_ns;
@@ -2682,7 +2690,7 @@ void put_mnt_ns(struct mnt_namespace *ns)
        br_write_unlock(&vfsmount_lock);
        up_write(&namespace_sem);
        release_mounts(&umount_list);
-       kfree(ns);
+       free_mnt_ns(ns);
 }
 
 struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
index 5a8e390..12b2ab5 100644 (file)
@@ -4,9 +4,10 @@
 
 struct mnt_namespace;
 struct fs_struct;
+struct user_namespace;
 
 extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *,
-               struct fs_struct *);
+               struct user_namespace *, struct fs_struct *);
 extern void put_mnt_ns(struct mnt_namespace *ns);
 
 extern const struct file_operations proc_mounts_operations;
index b8d4d87..7f8b051 100644 (file)
@@ -66,7 +66,7 @@ static struct nsproxy *create_new_namespaces(unsigned long flags,
        if (!new_nsp)
                return ERR_PTR(-ENOMEM);
 
-       new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, new_fs);
+       new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, task_cred_xxx(tsk, user_ns), new_fs);
        if (IS_ERR(new_nsp->mnt_ns)) {
                err = PTR_ERR(new_nsp->mnt_ns);
                goto out_ns;