diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2012-07-27 00:08:32 -0400 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2012-11-19 08:59:19 -0500 |
commit | 771b1371686e0a63e938ada28de020b9a0040f55 (patch) | |
tree | 1eb8891f19c43255febe2e801c33cbe7061e9a34 | |
parent | 8823c079ba7136dc1948d6f6dcb5f8022bde438e (diff) |
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: "Serge E. Hallyn" <serge@hallyn.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
-rw-r--r-- | fs/mount.h | 1 | ||||
-rw-r--r-- | fs/namespace.c | 24 | ||||
-rw-r--r-- | include/linux/mnt_namespace.h | 3 | ||||
-rw-r--r-- | kernel/nsproxy.c | 2 |
4 files changed, 20 insertions, 10 deletions
diff --git a/fs/mount.h b/fs/mount.h index e9c37dd3d00d..630fafc616bb 100644 --- a/fs/mount.h +++ b/fs/mount.h | |||
@@ -6,6 +6,7 @@ struct mnt_namespace { | |||
6 | atomic_t count; | 6 | atomic_t count; |
7 | struct mount * root; | 7 | struct mount * root; |
8 | struct list_head list; | 8 | struct list_head list; |
9 | struct user_namespace *user_ns; | ||
9 | u64 seq; /* Sequence number to prevent loops */ | 10 | u64 seq; /* Sequence number to prevent loops */ |
10 | wait_queue_head_t poll; | 11 | wait_queue_head_t poll; |
11 | int event; | 12 | int event; |
diff --git a/fs/namespace.c b/fs/namespace.c index d287e7e74644..207c7ba84ad3 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/export.h> | 12 | #include <linux/export.h> |
13 | #include <linux/capability.h> | 13 | #include <linux/capability.h> |
14 | #include <linux/mnt_namespace.h> | 14 | #include <linux/mnt_namespace.h> |
15 | #include <linux/user_namespace.h> | ||
15 | #include <linux/namei.h> | 16 | #include <linux/namei.h> |
16 | #include <linux/security.h> | 17 | #include <linux/security.h> |
17 | #include <linux/idr.h> | 18 | #include <linux/idr.h> |
@@ -2286,6 +2287,12 @@ dput_out: | |||
2286 | return retval; | 2287 | return retval; |
2287 | } | 2288 | } |
2288 | 2289 | ||
2290 | static void free_mnt_ns(struct mnt_namespace *ns) | ||
2291 | { | ||
2292 | put_user_ns(ns->user_ns); | ||
2293 | kfree(ns); | ||
2294 | } | ||
2295 | |||
2289 | /* | 2296 | /* |
2290 | * Assign a sequence number so we can detect when we attempt to bind | 2297 | * Assign a sequence number so we can detect when we attempt to bind |
2291 | * mount a reference to an older mount namespace into the current | 2298 | * mount a reference to an older mount namespace into the current |
@@ -2295,7 +2302,7 @@ dput_out: | |||
2295 | */ | 2302 | */ |
2296 | static atomic64_t mnt_ns_seq = ATOMIC64_INIT(1); | 2303 | static atomic64_t mnt_ns_seq = ATOMIC64_INIT(1); |
2297 | 2304 | ||
2298 | static struct mnt_namespace *alloc_mnt_ns(void) | 2305 | static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns) |
2299 | { | 2306 | { |
2300 | struct mnt_namespace *new_ns; | 2307 | struct mnt_namespace *new_ns; |
2301 | 2308 | ||
@@ -2308,6 +2315,7 @@ static struct mnt_namespace *alloc_mnt_ns(void) | |||
2308 | INIT_LIST_HEAD(&new_ns->list); | 2315 | INIT_LIST_HEAD(&new_ns->list); |
2309 | init_waitqueue_head(&new_ns->poll); | 2316 | init_waitqueue_head(&new_ns->poll); |
2310 | new_ns->event = 0; | 2317 | new_ns->event = 0; |
2318 | new_ns->user_ns = get_user_ns(user_ns); | ||
2311 | return new_ns; | 2319 | return new_ns; |
2312 | } | 2320 | } |
2313 | 2321 | ||
@@ -2316,7 +2324,7 @@ static struct mnt_namespace *alloc_mnt_ns(void) | |||
2316 | * copied from the namespace of the passed in task structure. | 2324 | * copied from the namespace of the passed in task structure. |
2317 | */ | 2325 | */ |
2318 | static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | 2326 | static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, |
2319 | struct fs_struct *fs) | 2327 | struct user_namespace *user_ns, struct fs_struct *fs) |
2320 | { | 2328 | { |
2321 | struct mnt_namespace *new_ns; | 2329 | struct mnt_namespace *new_ns; |
2322 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL; | 2330 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL; |
@@ -2324,7 +2332,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
2324 | struct mount *old = mnt_ns->root; | 2332 | struct mount *old = mnt_ns->root; |
2325 | struct mount *new; | 2333 | struct mount *new; |
2326 | 2334 | ||
2327 | new_ns = alloc_mnt_ns(); | 2335 | new_ns = alloc_mnt_ns(user_ns); |
2328 | if (IS_ERR(new_ns)) | 2336 | if (IS_ERR(new_ns)) |
2329 | return new_ns; | 2337 | return new_ns; |
2330 | 2338 | ||
@@ -2333,7 +2341,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
2333 | new = copy_tree(old, old->mnt.mnt_root, CL_COPY_ALL | CL_EXPIRE); | 2341 | new = copy_tree(old, old->mnt.mnt_root, CL_COPY_ALL | CL_EXPIRE); |
2334 | if (IS_ERR(new)) { | 2342 | if (IS_ERR(new)) { |
2335 | up_write(&namespace_sem); | 2343 | up_write(&namespace_sem); |
2336 | kfree(new_ns); | 2344 | free_mnt_ns(new_ns); |
2337 | return ERR_CAST(new); | 2345 | return ERR_CAST(new); |
2338 | } | 2346 | } |
2339 | new_ns->root = new; | 2347 | new_ns->root = new; |
@@ -2374,7 +2382,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
2374 | } | 2382 | } |
2375 | 2383 | ||
2376 | struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, | 2384 | struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, |
2377 | struct fs_struct *new_fs) | 2385 | struct user_namespace *user_ns, struct fs_struct *new_fs) |
2378 | { | 2386 | { |
2379 | struct mnt_namespace *new_ns; | 2387 | struct mnt_namespace *new_ns; |
2380 | 2388 | ||
@@ -2384,7 +2392,7 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, | |||
2384 | if (!(flags & CLONE_NEWNS)) | 2392 | if (!(flags & CLONE_NEWNS)) |
2385 | return ns; | 2393 | return ns; |
2386 | 2394 | ||
2387 | new_ns = dup_mnt_ns(ns, new_fs); | 2395 | new_ns = dup_mnt_ns(ns, user_ns, new_fs); |
2388 | 2396 | ||
2389 | put_mnt_ns(ns); | 2397 | put_mnt_ns(ns); |
2390 | return new_ns; | 2398 | return new_ns; |
@@ -2396,7 +2404,7 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, | |||
2396 | */ | 2404 | */ |
2397 | static struct mnt_namespace *create_mnt_ns(struct vfsmount *m) | 2405 | static struct mnt_namespace *create_mnt_ns(struct vfsmount *m) |
2398 | { | 2406 | { |
2399 | struct mnt_namespace *new_ns = alloc_mnt_ns(); | 2407 | struct mnt_namespace *new_ns = alloc_mnt_ns(&init_user_ns); |
2400 | if (!IS_ERR(new_ns)) { | 2408 | if (!IS_ERR(new_ns)) { |
2401 | struct mount *mnt = real_mount(m); | 2409 | struct mount *mnt = real_mount(m); |
2402 | mnt->mnt_ns = new_ns; | 2410 | mnt->mnt_ns = new_ns; |
@@ -2682,7 +2690,7 @@ void put_mnt_ns(struct mnt_namespace *ns) | |||
2682 | br_write_unlock(&vfsmount_lock); | 2690 | br_write_unlock(&vfsmount_lock); |
2683 | up_write(&namespace_sem); | 2691 | up_write(&namespace_sem); |
2684 | release_mounts(&umount_list); | 2692 | release_mounts(&umount_list); |
2685 | kfree(ns); | 2693 | free_mnt_ns(ns); |
2686 | } | 2694 | } |
2687 | 2695 | ||
2688 | struct vfsmount *kern_mount_data(struct file_system_type *type, void *data) | 2696 | struct vfsmount *kern_mount_data(struct file_system_type *type, void *data) |
diff --git a/include/linux/mnt_namespace.h b/include/linux/mnt_namespace.h index 5a8e3903d770..12b2ab510323 100644 --- a/include/linux/mnt_namespace.h +++ b/include/linux/mnt_namespace.h | |||
@@ -4,9 +4,10 @@ | |||
4 | 4 | ||
5 | struct mnt_namespace; | 5 | struct mnt_namespace; |
6 | struct fs_struct; | 6 | struct fs_struct; |
7 | struct user_namespace; | ||
7 | 8 | ||
8 | extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *, | 9 | extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *, |
9 | struct fs_struct *); | 10 | struct user_namespace *, struct fs_struct *); |
10 | extern void put_mnt_ns(struct mnt_namespace *ns); | 11 | extern void put_mnt_ns(struct mnt_namespace *ns); |
11 | 12 | ||
12 | extern const struct file_operations proc_mounts_operations; | 13 | extern const struct file_operations proc_mounts_operations; |
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index b8d4d8709d70..7f8b051fc19f 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c | |||
@@ -66,7 +66,7 @@ static struct nsproxy *create_new_namespaces(unsigned long flags, | |||
66 | if (!new_nsp) | 66 | if (!new_nsp) |
67 | return ERR_PTR(-ENOMEM); | 67 | return ERR_PTR(-ENOMEM); |
68 | 68 | ||
69 | new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, new_fs); | 69 | new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, task_cred_xxx(tsk, user_ns), new_fs); |
70 | if (IS_ERR(new_nsp->mnt_ns)) { | 70 | if (IS_ERR(new_nsp->mnt_ns)) { |
71 | err = PTR_ERR(new_nsp->mnt_ns); | 71 | err = PTR_ERR(new_nsp->mnt_ns); |
72 | goto out_ns; | 72 | goto out_ns; |