diff options
Diffstat (limited to 'kernel/user_namespace.c')
-rw-r--r-- | kernel/user_namespace.c | 65 |
1 files changed, 30 insertions, 35 deletions
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 532858fa5b88..79084311ee57 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c | |||
@@ -9,60 +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 | int n; | 26 | int n; |
23 | 27 | ||
24 | ns = kmalloc(sizeof(struct user_namespace), GFP_KERNEL); | 28 | ns = kmalloc(sizeof(struct user_namespace), GFP_KERNEL); |
25 | if (!ns) | 29 | if (!ns) |
26 | return ERR_PTR(-ENOMEM); | 30 | return -ENOMEM; |
27 | 31 | ||
28 | kref_init(&ns->kref); | 32 | kref_init(&ns->kref); |
29 | 33 | ||
30 | for (n = 0; n < UIDHASH_SZ; ++n) | 34 | for (n = 0; n < UIDHASH_SZ; ++n) |
31 | INIT_HLIST_HEAD(ns->uidhash_table + n); | 35 | INIT_HLIST_HEAD(ns->uidhash_table + n); |
32 | 36 | ||
33 | /* Insert new root user. */ | 37 | /* Alloc new root user. */ |
34 | ns->root_user = alloc_uid(ns, 0); | 38 | root_user = alloc_uid(ns, 0); |
35 | if (!ns->root_user) { | 39 | if (!root_user) { |
36 | kfree(ns); | 40 | kfree(ns); |
37 | return ERR_PTR(-ENOMEM); | 41 | return -ENOMEM; |
38 | } | 42 | } |
39 | 43 | ||
40 | /* Reset current->user with a new one */ | 44 | /* set the new root user in the credentials under preparation */ |
41 | new_user = alloc_uid(ns, current->uid); | 45 | ns->creator = new->user; |
42 | if (!new_user) { | 46 | new->user = root_user; |
43 | free_uid(ns->root_user); | 47 | new->uid = new->euid = new->suid = new->fsuid = 0; |
44 | kfree(ns); | 48 | new->gid = new->egid = new->sgid = new->fsgid = 0; |
45 | return ERR_PTR(-ENOMEM); | 49 | put_group_info(new->group_info); |
46 | } | 50 | new->group_info = get_group_info(&init_groups); |
47 | 51 | #ifdef CONFIG_KEYS | |
48 | switch_uid(new_user); | 52 | key_put(new->request_key_auth); |
49 | return ns; | 53 | new->request_key_auth = NULL; |
50 | } | 54 | #endif |
51 | 55 | /* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */ | |
52 | struct user_namespace * copy_user_ns(int flags, struct user_namespace *old_ns) | ||
53 | { | ||
54 | struct user_namespace *new_ns; | ||
55 | |||
56 | BUG_ON(!old_ns); | ||
57 | get_user_ns(old_ns); | ||
58 | |||
59 | if (!(flags & CLONE_NEWUSER)) | ||
60 | return old_ns; | ||
61 | 56 | ||
62 | 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); | ||
63 | 59 | ||
64 | put_user_ns(old_ns); | 60 | return 0; |
65 | return new_ns; | ||
66 | } | 61 | } |
67 | 62 | ||
68 | void free_user_ns(struct kref *kref) | 63 | void free_user_ns(struct kref *kref) |
@@ -70,7 +65,7 @@ void free_user_ns(struct kref *kref) | |||
70 | struct user_namespace *ns; | 65 | struct user_namespace *ns; |
71 | 66 | ||
72 | ns = container_of(kref, struct user_namespace, kref); | 67 | ns = container_of(kref, struct user_namespace, kref); |
73 | release_uids(ns); | 68 | free_uid(ns->creator); |
74 | kfree(ns); | 69 | kfree(ns); |
75 | } | 70 | } |
76 | EXPORT_SYMBOL(free_user_ns); | 71 | EXPORT_SYMBOL(free_user_ns); |