diff options
Diffstat (limited to 'kernel/user_namespace.c')
-rw-r--r-- | kernel/user_namespace.c | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 3d7964209774..89a27e8b17fb 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c | |||
@@ -21,6 +21,45 @@ EXPORT_SYMBOL_GPL(init_user_ns); | |||
21 | 21 | ||
22 | #ifdef CONFIG_USER_NS | 22 | #ifdef CONFIG_USER_NS |
23 | 23 | ||
24 | /* | ||
25 | * Clone a new ns copying an original user ns, setting refcount to 1 | ||
26 | * @old_ns: namespace to clone | ||
27 | * Return NULL on error (failure to kmalloc), new ns otherwise | ||
28 | */ | ||
29 | static struct user_namespace *clone_user_ns(struct user_namespace *old_ns) | ||
30 | { | ||
31 | struct user_namespace *ns; | ||
32 | struct user_struct *new_user; | ||
33 | int n; | ||
34 | |||
35 | ns = kmalloc(sizeof(struct user_namespace), GFP_KERNEL); | ||
36 | if (!ns) | ||
37 | return NULL; | ||
38 | |||
39 | kref_init(&ns->kref); | ||
40 | |||
41 | for (n = 0; n < UIDHASH_SZ; ++n) | ||
42 | INIT_LIST_HEAD(ns->uidhash_table + n); | ||
43 | |||
44 | /* Insert new root user. */ | ||
45 | ns->root_user = alloc_uid(ns, 0); | ||
46 | if (!ns->root_user) { | ||
47 | kfree(ns); | ||
48 | return NULL; | ||
49 | } | ||
50 | |||
51 | /* Reset current->user with a new one */ | ||
52 | new_user = alloc_uid(ns, current->uid); | ||
53 | if (!new_user) { | ||
54 | free_uid(ns->root_user); | ||
55 | kfree(ns); | ||
56 | return NULL; | ||
57 | } | ||
58 | |||
59 | switch_uid(new_user); | ||
60 | return ns; | ||
61 | } | ||
62 | |||
24 | struct user_namespace * copy_user_ns(int flags, struct user_namespace *old_ns) | 63 | struct user_namespace * copy_user_ns(int flags, struct user_namespace *old_ns) |
25 | { | 64 | { |
26 | struct user_namespace *new_ns; | 65 | struct user_namespace *new_ns; |
@@ -28,7 +67,12 @@ struct user_namespace * copy_user_ns(int flags, struct user_namespace *old_ns) | |||
28 | BUG_ON(!old_ns); | 67 | BUG_ON(!old_ns); |
29 | get_user_ns(old_ns); | 68 | get_user_ns(old_ns); |
30 | 69 | ||
31 | new_ns = old_ns; | 70 | if (!(flags & CLONE_NEWUSER)) |
71 | return old_ns; | ||
72 | |||
73 | new_ns = clone_user_ns(old_ns); | ||
74 | |||
75 | put_user_ns(old_ns); | ||
32 | return new_ns; | 76 | return new_ns; |
33 | } | 77 | } |
34 | 78 | ||