···274274 struct thread_group_cred *tgcred;275275#endif276276 struct cred *new;277277+ int ret;277278278279 mutex_init(&p->cred_exec_mutex);279280···294293 if (!new)295294 return -ENOMEM;296295296296+ if (clone_flags & CLONE_NEWUSER) {297297+ ret = create_user_ns(new);298298+ if (ret < 0)299299+ goto error_put;300300+ }301301+297302#ifdef CONFIG_KEYS298303 /* new threads get their own thread keyrings if their parent already299304 * had one */···316309 if (!(clone_flags & CLONE_THREAD)) {317310 tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);318311 if (!tgcred) {319319- put_cred(new);320320- return -ENOMEM;312312+ ret = -ENOMEM;313313+ goto error_put;321314 }322315 atomic_set(&tgcred->usage, 1);323316 spin_lock_init(&tgcred->lock);···332325 atomic_inc(&new->user->processes);333326 p->cred = p->real_cred = get_cred(new);334327 return 0;328328+329329+error_put:330330+ put_cred(new);331331+ return ret;335332}336333337334/**
+16-3
kernel/fork.c
···976976 if (atomic_read(&p->real_cred->user->processes) >=977977 p->signal->rlim[RLIMIT_NPROC].rlim_cur) {978978 if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) &&979979- p->real_cred->user != current->nsproxy->user_ns->root_user)979979+ p->real_cred->user != INIT_USER)980980 goto bad_fork_free;981981 }982982···13351335 long nr;1336133613371337 /*13381338+ * Do some preliminary argument and permissions checking before we13391339+ * actually start allocating stuff13401340+ */13411341+ if (clone_flags & CLONE_NEWUSER) {13421342+ if (clone_flags & CLONE_THREAD)13431343+ return -EINVAL;13441344+ /* hopefully this check will go away when userns support is13451345+ * complete13461346+ */13471347+ if (!capable(CAP_SYS_ADMIN))13481348+ return -EPERM;13491349+ }13501350+13511351+ /*13381352 * We hope to recycle these flags after 2.6.2613391353 */13401354 if (unlikely(clone_flags & CLONE_STOPPED)) {···15951581 err = -EINVAL;15961582 if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|15971583 CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|15981598- CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWUSER|15991599- CLONE_NEWNET))15841584+ CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET))16001585 goto bad_unshare_out;1601158616021587 /*
+2-13
kernel/nsproxy.c
···8080 goto out_pid;8181 }82828383- new_nsp->user_ns = copy_user_ns(flags, tsk->nsproxy->user_ns);8484- if (IS_ERR(new_nsp->user_ns)) {8585- err = PTR_ERR(new_nsp->user_ns);8686- goto out_user;8787- }8888-8983 new_nsp->net_ns = copy_net_ns(flags, tsk->nsproxy->net_ns);9084 if (IS_ERR(new_nsp->net_ns)) {9185 err = PTR_ERR(new_nsp->net_ns);···8995 return new_nsp;90969197out_net:9292- if (new_nsp->user_ns)9393- put_user_ns(new_nsp->user_ns);9494-out_user:9598 if (new_nsp->pid_ns)9699 put_pid_ns(new_nsp->pid_ns);97100out_pid:···121130 get_nsproxy(old_ns);122131123132 if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |124124- CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNET)))133133+ CLONE_NEWPID | CLONE_NEWNET)))125134 return 0;126135127136 if (!capable(CAP_SYS_ADMIN)) {···164173 put_ipc_ns(ns->ipc_ns);165174 if (ns->pid_ns)166175 put_pid_ns(ns->pid_ns);167167- if (ns->user_ns)168168- put_user_ns(ns->user_ns);169176 put_net(ns->net_ns);170177 kmem_cache_free(nsproxy_cachep, ns);171178}···178189 int err = 0;179190180191 if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |181181- CLONE_NEWUSER | CLONE_NEWNET)))192192+ CLONE_NEWNET)))182193 return 0;183194184195 if (!capable(CAP_SYS_ADMIN))
···20202121struct user_namespace init_user_ns = {2222 .kref = {2323- .refcount = ATOMIC_INIT(2),2323+ .refcount = ATOMIC_INIT(1),2424 },2525- .root_user = &root_user,2525+ .creator = &root_user,2626};2727EXPORT_SYMBOL_GPL(init_user_ns);2828···4848 */4949static DEFINE_SPINLOCK(uidhash_lock);50505151+/* root_user.__count is 2, 1 for init task cred, 1 for init_user_ns->creator */5152struct user_struct root_user = {5252- .__count = ATOMIC_INIT(1),5353+ .__count = ATOMIC_INIT(2),5354 .processes = ATOMIC_INIT(1),5455 .files = ATOMIC_INIT(0),5556 .sigpending = ATOMIC_INIT(0),5657 .locked_shm = 0,5858+ .user_ns = &init_user_ns,5759#ifdef CONFIG_USER_SCHED5860 .tg = &init_task_group,5961#endif···316314 * IRQ state (as stored in flags) is restored and uidhash_lock released317315 * upon function exit.318316 */319319-static inline void free_user(struct user_struct *up, unsigned long flags)317317+static void free_user(struct user_struct *up, unsigned long flags)320318{321319 /* restore back the count */322320 atomic_inc(&up->__count);323321 spin_unlock_irqrestore(&uidhash_lock, flags);324322323323+ put_user_ns(up->user_ns);325324 INIT_WORK(&up->work, remove_user_sysfs_dir);326325 schedule_work(&up->work);327326}···338335 * IRQ state (as stored in flags) is restored and uidhash_lock released339336 * upon function exit.340337 */341341-static inline void free_user(struct user_struct *up, unsigned long flags)338338+static void free_user(struct user_struct *up, unsigned long flags)342339{343340 uid_hash_remove(up);344341 spin_unlock_irqrestore(&uidhash_lock, flags);345342 sched_destroy_user(up);346343 key_put(up->uid_keyring);347344 key_put(up->session_keyring);345345+ put_user_ns(up->user_ns);348346 kmem_cache_free(uid_cachep, up);349347}350348···361357{362358 struct user_struct *ret;363359 unsigned long flags;364364- struct user_namespace *ns = current->nsproxy->user_ns;360360+ struct user_namespace *ns = current_user_ns();365361366362 spin_lock_irqsave(&uidhash_lock, flags);367363 ret = uid_hash_find(uid, uidhashentry(ns, uid));···408404 if (sched_create_user(new) < 0)409405 goto out_free_user;410406407407+ new->user_ns = get_user_ns(ns);408408+411409 if (uids_user_create(new))412410 goto out_destoy_sched;413411···433427 up = new;434428 }435429 spin_unlock_irq(&uidhash_lock);436436-437430 }438431439432 uids_mutex_unlock();···441436442437out_destoy_sched:443438 sched_destroy_user(new);439439+ put_user_ns(new->user_ns);444440out_free_user:445441 kmem_cache_free(uid_cachep, new);446442out_unlock:447443 uids_mutex_unlock();448444 return NULL;449445}450450-451451-#ifdef CONFIG_USER_NS452452-void release_uids(struct user_namespace *ns)453453-{454454- int i;455455- unsigned long flags;456456- struct hlist_head *head;457457- struct hlist_node *nd;458458-459459- spin_lock_irqsave(&uidhash_lock, flags);460460- /*461461- * collapse the chains so that the user_struct-s will462462- * be still alive, but not in hashes. subsequent free_uid()463463- * will free them.464464- */465465- for (i = 0; i < UIDHASH_SZ; i++) {466466- head = ns->uidhash_table + i;467467- while (!hlist_empty(head)) {468468- nd = head->first;469469- hlist_del_init(nd);470470- }471471- }472472- spin_unlock_irqrestore(&uidhash_lock, flags);473473-474474- free_uid(ns->root_user);475475-}476476-#endif477446478447static int __init uid_cache_init(void)479448{
+30-45
kernel/user_namespace.c
···99#include <linux/nsproxy.h>1010#include <linux/slab.h>1111#include <linux/user_namespace.h>1212+#include <linux/cred.h>12131314/*1414- * Clone a new ns copying an original user ns, setting refcount to 11515- * @old_ns: namespace to clone1616- * Return NULL on error (failure to kmalloc), new ns otherwise1515+ * Create a new user namespace, deriving the creator from the user in the1616+ * passed credentials, and replacing that user with the new root user for the1717+ * new namespace.1818+ *1919+ * This is called by copy_creds(), which will finish setting the target task's2020+ * credentials.1721 */1818-static struct user_namespace *clone_user_ns(struct user_namespace *old_ns)2222+int create_user_ns(struct cred *new)1923{2024 struct user_namespace *ns;2121- struct user_struct *new_user;2222- struct cred *new;2525+ struct user_struct *root_user;2326 int n;24272528 ns = kmalloc(sizeof(struct user_namespace), GFP_KERNEL);2629 if (!ns)2727- return ERR_PTR(-ENOMEM);3030+ return -ENOMEM;28312932 kref_init(&ns->kref);30333134 for (n = 0; n < UIDHASH_SZ; ++n)3235 INIT_HLIST_HEAD(ns->uidhash_table + n);33363434- /* Insert new root user. */3535- ns->root_user = alloc_uid(ns, 0);3636- if (!ns->root_user) {3737+ /* Alloc new root user. */3838+ root_user = alloc_uid(ns, 0);3939+ if (!root_user) {3740 kfree(ns);3838- return ERR_PTR(-ENOMEM);4141+ return -ENOMEM;3942 }40434141- /* Reset current->user with a new one */4242- new_user = alloc_uid(ns, current_uid());4343- if (!new_user) {4444- free_uid(ns->root_user);4545- kfree(ns);4646- return ERR_PTR(-ENOMEM);4747- }4444+ /* set the new root user in the credentials under preparation */4545+ ns->creator = new->user;4646+ new->user = root_user;4747+ new->uid = new->euid = new->suid = new->fsuid = 0;4848+ new->gid = new->egid = new->sgid = new->fsgid = 0;4949+ put_group_info(new->group_info);5050+ new->group_info = get_group_info(&init_groups);5151+#ifdef CONFIG_KEYS5252+ key_put(new->request_key_auth);5353+ new->request_key_auth = NULL;5454+#endif5555+ /* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */48564949- /* Install the new user */5050- new = prepare_creds();5151- if (!new) {5252- free_uid(new_user);5353- free_uid(ns->root_user);5454- kfree(ns);5555- }5656- free_uid(new->user);5757- new->user = new_user;5858- commit_creds(new);5959- return ns;6060-}5757+ /* alloc_uid() incremented the userns refcount. Just set it to 1 */5858+ kref_set(&ns->kref, 1);61596262-struct user_namespace * copy_user_ns(int flags, struct user_namespace *old_ns)6363-{6464- struct user_namespace *new_ns;6565-6666- BUG_ON(!old_ns);6767- get_user_ns(old_ns);6868-6969- if (!(flags & CLONE_NEWUSER))7070- return old_ns;7171-7272- new_ns = clone_user_ns(old_ns);7373-7474- put_user_ns(old_ns);7575- return new_ns;6060+ return 0;7661}77627863void free_user_ns(struct kref *kref)···6580 struct user_namespace *ns;66816782 ns = container_of(kref, struct user_namespace, kref);6868- release_uids(ns);8383+ free_uid(ns->creator);6984 kfree(ns);7085}7186EXPORT_SYMBOL(free_user_ns);