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); |
