diff options
| author | James Morris <jmorris@namei.org> | 2008-11-26 00:26:44 -0500 |
|---|---|---|
| committer | James Morris <jmorris@namei.org> | 2008-11-26 00:26:44 -0500 |
| commit | 3496f92beb9aa99ef21fccc154a36c7698e9c538 (patch) | |
| tree | 2492602c6316b654378c3b557e206923956e59f4 /kernel/user_namespace.c | |
| parent | 200036ca9b3f0b2250912142552ce56682190f95 (diff) | |
| parent | 6ded6ab9be4f6164aef1c527407c1b94f0929799 (diff) | |
Merge branch 'serge-next' into next
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); |
