diff options
Diffstat (limited to 'kernel/user_namespace.c')
-rw-r--r-- | kernel/user_namespace.c | 75 |
1 files changed, 30 insertions, 45 deletions
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 0d9c51d67333..79084311ee57 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c | |||
@@ -9,70 +9,55 @@ | |||
9 | #include <linux/nsproxy.h> | 9 | #include <linux/nsproxy.h> |
10 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
11 | #include <linux/user_namespace.h> | 11 | #include <linux/user_namespace.h> |
12 | #include <linux/cred.h> | ||
12 | 13 | ||
13 | /* | 14 | /* |
14 | * Clone a new ns copying an original user ns, setting refcount to 1 | 15 | * Create a new user namespace, deriving the creator from the user in the |
15 | * @old_ns: namespace to clone | 16 | * passed credentials, and replacing that user with the new root user for the |
16 | * Return NULL on error (failure to kmalloc), new ns otherwise | 17 | * new namespace. |
18 | * | ||
19 | * This is called by copy_creds(), which will finish setting the target task's | ||
20 | * credentials. | ||
17 | */ | 21 | */ |
18 | static struct user_namespace *clone_user_ns(struct user_namespace *old_ns) | 22 | int create_user_ns(struct cred *new) |
19 | { | 23 | { |
20 | struct user_namespace *ns; | 24 | struct user_namespace *ns; |
21 | struct user_struct *new_user; | 25 | struct user_struct *root_user; |
22 | struct cred *new; | ||
23 | int n; | 26 | int n; |
24 | 27 | ||
25 | ns = kmalloc(sizeof(struct user_namespace), GFP_KERNEL); | 28 | ns = kmalloc(sizeof(struct user_namespace), GFP_KERNEL); |
26 | if (!ns) | 29 | if (!ns) |
27 | return ERR_PTR(-ENOMEM); | 30 | return -ENOMEM; |
28 | 31 | ||
29 | kref_init(&ns->kref); | 32 | kref_init(&ns->kref); |
30 | 33 | ||
31 | for (n = 0; n < UIDHASH_SZ; ++n) | 34 | for (n = 0; n < UIDHASH_SZ; ++n) |
32 | INIT_HLIST_HEAD(ns->uidhash_table + n); | 35 | INIT_HLIST_HEAD(ns->uidhash_table + n); |
33 | 36 | ||
34 | /* Insert new root user. */ | 37 | /* Alloc new root user. */ |
35 | ns->root_user = alloc_uid(ns, 0); | 38 | root_user = alloc_uid(ns, 0); |
36 | if (!ns->root_user) { | 39 | if (!root_user) { |
37 | kfree(ns); | 40 | kfree(ns); |
38 | return ERR_PTR(-ENOMEM); | 41 | return -ENOMEM; |
39 | } | 42 | } |
40 | 43 | ||
41 | /* Reset current->user with a new one */ | 44 | /* set the new root user in the credentials under preparation */ |
42 | new_user = alloc_uid(ns, current_uid()); | 45 | ns->creator = new->user; |
43 | if (!new_user) { | 46 | new->user = root_user; |
44 | free_uid(ns->root_user); | 47 | new->uid = new->euid = new->suid = new->fsuid = 0; |
45 | kfree(ns); | 48 | new->gid = new->egid = new->sgid = new->fsgid = 0; |
46 | return ERR_PTR(-ENOMEM); | 49 | put_group_info(new->group_info); |
47 | } | 50 | new->group_info = get_group_info(&init_groups); |
48 | 51 | #ifdef CONFIG_KEYS | |
49 | /* Install the new user */ | 52 | key_put(new->request_key_auth); |
50 | new = prepare_creds(); | 53 | new->request_key_auth = NULL; |
51 | if (!new) { | 54 | #endif |
52 | free_uid(new_user); | 55 | /* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */ |
53 | free_uid(ns->root_user); | ||
54 | kfree(ns); | ||
55 | } | ||
56 | free_uid(new->user); | ||
57 | new->user = new_user; | ||
58 | commit_creds(new); | ||
59 | return ns; | ||
60 | } | ||
61 | |||
62 | struct user_namespace * copy_user_ns(int flags, struct user_namespace *old_ns) | ||
63 | { | ||
64 | struct user_namespace *new_ns; | ||
65 | |||
66 | BUG_ON(!old_ns); | ||
67 | get_user_ns(old_ns); | ||
68 | |||
69 | if (!(flags & CLONE_NEWUSER)) | ||
70 | return old_ns; | ||
71 | 56 | ||
72 | new_ns = clone_user_ns(old_ns); | 57 | /* alloc_uid() incremented the userns refcount. Just set it to 1 */ |
58 | kref_set(&ns->kref, 1); | ||
73 | 59 | ||
74 | put_user_ns(old_ns); | 60 | return 0; |
75 | return new_ns; | ||
76 | } | 61 | } |
77 | 62 | ||
78 | void free_user_ns(struct kref *kref) | 63 | void free_user_ns(struct kref *kref) |
@@ -80,7 +65,7 @@ void free_user_ns(struct kref *kref) | |||
80 | struct user_namespace *ns; | 65 | struct user_namespace *ns; |
81 | 66 | ||
82 | ns = container_of(kref, struct user_namespace, kref); | 67 | ns = container_of(kref, struct user_namespace, kref); |
83 | release_uids(ns); | 68 | free_uid(ns->creator); |
84 | kfree(ns); | 69 | kfree(ns); |
85 | } | 70 | } |
86 | EXPORT_SYMBOL(free_user_ns); | 71 | EXPORT_SYMBOL(free_user_ns); |