Commit 771b1371 authored by Eric W. Biederman's avatar Eric W. Biederman

vfs: Add a user namespace reference from struct mnt_namespace

This will allow for support for unprivileged mounts in a new user namespace.
Acked-by: default avatar"Serge E. Hallyn" <serge@hallyn.com>
Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
parent 8823c079
...@@ -6,6 +6,7 @@ struct mnt_namespace { ...@@ -6,6 +6,7 @@ struct mnt_namespace {
atomic_t count; atomic_t count;
struct mount * root; struct mount * root;
struct list_head list; struct list_head list;
struct user_namespace *user_ns;
u64 seq; /* Sequence number to prevent loops */ u64 seq; /* Sequence number to prevent loops */
wait_queue_head_t poll; wait_queue_head_t poll;
int event; int event;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/mnt_namespace.h> #include <linux/mnt_namespace.h>
#include <linux/user_namespace.h>
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/idr.h> #include <linux/idr.h>
...@@ -2286,6 +2287,12 @@ long do_mount(const char *dev_name, const char *dir_name, ...@@ -2286,6 +2287,12 @@ long do_mount(const char *dev_name, const char *dir_name,
return retval; 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 * Assign a sequence number so we can detect when we attempt to bind
* mount a reference to an older mount namespace into the current * mount a reference to an older mount namespace into the current
...@@ -2295,7 +2302,7 @@ long do_mount(const char *dev_name, const char *dir_name, ...@@ -2295,7 +2302,7 @@ long do_mount(const char *dev_name, const char *dir_name,
*/ */
static atomic64_t mnt_ns_seq = ATOMIC64_INIT(1); 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; struct mnt_namespace *new_ns;
...@@ -2308,6 +2315,7 @@ static struct mnt_namespace *alloc_mnt_ns(void) ...@@ -2308,6 +2315,7 @@ static struct mnt_namespace *alloc_mnt_ns(void)
INIT_LIST_HEAD(&new_ns->list); INIT_LIST_HEAD(&new_ns->list);
init_waitqueue_head(&new_ns->poll); init_waitqueue_head(&new_ns->poll);
new_ns->event = 0; new_ns->event = 0;
new_ns->user_ns = get_user_ns(user_ns);
return new_ns; return new_ns;
} }
...@@ -2316,7 +2324,7 @@ static struct mnt_namespace *alloc_mnt_ns(void) ...@@ -2316,7 +2324,7 @@ static struct mnt_namespace *alloc_mnt_ns(void)
* copied from the namespace of the passed in task structure. * copied from the namespace of the passed in task structure.
*/ */
static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, 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 mnt_namespace *new_ns;
struct vfsmount *rootmnt = NULL, *pwdmnt = NULL; struct vfsmount *rootmnt = NULL, *pwdmnt = NULL;
...@@ -2324,7 +2332,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, ...@@ -2324,7 +2332,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
struct mount *old = mnt_ns->root; struct mount *old = mnt_ns->root;
struct mount *new; struct mount *new;
new_ns = alloc_mnt_ns(); new_ns = alloc_mnt_ns(user_ns);
if (IS_ERR(new_ns)) if (IS_ERR(new_ns))
return new_ns; return new_ns;
...@@ -2333,7 +2341,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_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); new = copy_tree(old, old->mnt.mnt_root, CL_COPY_ALL | CL_EXPIRE);
if (IS_ERR(new)) { if (IS_ERR(new)) {
up_write(&namespace_sem); up_write(&namespace_sem);
kfree(new_ns); free_mnt_ns(new_ns);
return ERR_CAST(new); return ERR_CAST(new);
} }
new_ns->root = new; new_ns->root = new;
...@@ -2374,7 +2382,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, ...@@ -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 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; struct mnt_namespace *new_ns;
...@@ -2384,7 +2392,7 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, ...@@ -2384,7 +2392,7 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
if (!(flags & CLONE_NEWNS)) if (!(flags & CLONE_NEWNS))
return ns; return ns;
new_ns = dup_mnt_ns(ns, new_fs); new_ns = dup_mnt_ns(ns, user_ns, new_fs);
put_mnt_ns(ns); put_mnt_ns(ns);
return new_ns; return new_ns;
...@@ -2396,7 +2404,7 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *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) 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)) { if (!IS_ERR(new_ns)) {
struct mount *mnt = real_mount(m); struct mount *mnt = real_mount(m);
mnt->mnt_ns = new_ns; mnt->mnt_ns = new_ns;
...@@ -2682,7 +2690,7 @@ void put_mnt_ns(struct mnt_namespace *ns) ...@@ -2682,7 +2690,7 @@ void put_mnt_ns(struct mnt_namespace *ns)
br_write_unlock(&vfsmount_lock); br_write_unlock(&vfsmount_lock);
up_write(&namespace_sem); up_write(&namespace_sem);
release_mounts(&umount_list); release_mounts(&umount_list);
kfree(ns); free_mnt_ns(ns);
} }
struct vfsmount *kern_mount_data(struct file_system_type *type, void *data) struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
......
...@@ -4,9 +4,10 @@ ...@@ -4,9 +4,10 @@
struct mnt_namespace; struct mnt_namespace;
struct fs_struct; struct fs_struct;
struct user_namespace;
extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_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 void put_mnt_ns(struct mnt_namespace *ns);
extern const struct file_operations proc_mounts_operations; extern const struct file_operations proc_mounts_operations;
......
...@@ -66,7 +66,7 @@ static struct nsproxy *create_new_namespaces(unsigned long flags, ...@@ -66,7 +66,7 @@ static struct nsproxy *create_new_namespaces(unsigned long flags,
if (!new_nsp) if (!new_nsp)
return ERR_PTR(-ENOMEM); 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)) { if (IS_ERR(new_nsp->mnt_ns)) {
err = PTR_ERR(new_nsp->mnt_ns); err = PTR_ERR(new_nsp->mnt_ns);
goto out_ns; goto out_ns;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment