diff options
Diffstat (limited to 'kernel/user.c')
-rw-r--r-- | kernel/user.c | 47 |
1 files changed, 13 insertions, 34 deletions
diff --git a/kernel/user.c b/kernel/user.c index d476307dd4b0..c0ef3a464438 100644 --- a/kernel/user.c +++ b/kernel/user.c | |||
@@ -20,9 +20,9 @@ | |||
20 | 20 | ||
21 | struct user_namespace init_user_ns = { | 21 | struct user_namespace init_user_ns = { |
22 | .kref = { | 22 | .kref = { |
23 | .refcount = ATOMIC_INIT(2), | 23 | .refcount = ATOMIC_INIT(1), |
24 | }, | 24 | }, |
25 | .root_user = &root_user, | 25 | .creator = &root_user, |
26 | }; | 26 | }; |
27 | EXPORT_SYMBOL_GPL(init_user_ns); | 27 | EXPORT_SYMBOL_GPL(init_user_ns); |
28 | 28 | ||
@@ -48,12 +48,14 @@ static struct kmem_cache *uid_cachep; | |||
48 | */ | 48 | */ |
49 | static DEFINE_SPINLOCK(uidhash_lock); | 49 | static DEFINE_SPINLOCK(uidhash_lock); |
50 | 50 | ||
51 | /* root_user.__count is 2, 1 for init task cred, 1 for init_user_ns->creator */ | ||
51 | struct user_struct root_user = { | 52 | struct user_struct root_user = { |
52 | .__count = ATOMIC_INIT(1), | 53 | .__count = ATOMIC_INIT(2), |
53 | .processes = ATOMIC_INIT(1), | 54 | .processes = ATOMIC_INIT(1), |
54 | .files = ATOMIC_INIT(0), | 55 | .files = ATOMIC_INIT(0), |
55 | .sigpending = ATOMIC_INIT(0), | 56 | .sigpending = ATOMIC_INIT(0), |
56 | .locked_shm = 0, | 57 | .locked_shm = 0, |
58 | .user_ns = &init_user_ns, | ||
57 | #ifdef CONFIG_USER_SCHED | 59 | #ifdef CONFIG_USER_SCHED |
58 | .tg = &init_task_group, | 60 | .tg = &init_task_group, |
59 | #endif | 61 | #endif |
@@ -314,12 +316,13 @@ done: | |||
314 | * IRQ state (as stored in flags) is restored and uidhash_lock released | 316 | * IRQ state (as stored in flags) is restored and uidhash_lock released |
315 | * upon function exit. | 317 | * upon function exit. |
316 | */ | 318 | */ |
317 | static inline void free_user(struct user_struct *up, unsigned long flags) | 319 | static void free_user(struct user_struct *up, unsigned long flags) |
318 | { | 320 | { |
319 | /* restore back the count */ | 321 | /* restore back the count */ |
320 | atomic_inc(&up->__count); | 322 | atomic_inc(&up->__count); |
321 | spin_unlock_irqrestore(&uidhash_lock, flags); | 323 | spin_unlock_irqrestore(&uidhash_lock, flags); |
322 | 324 | ||
325 | put_user_ns(up->user_ns); | ||
323 | INIT_WORK(&up->work, remove_user_sysfs_dir); | 326 | INIT_WORK(&up->work, remove_user_sysfs_dir); |
324 | schedule_work(&up->work); | 327 | schedule_work(&up->work); |
325 | } | 328 | } |
@@ -335,13 +338,14 @@ static inline void uids_mutex_unlock(void) { } | |||
335 | * IRQ state (as stored in flags) is restored and uidhash_lock released | 338 | * IRQ state (as stored in flags) is restored and uidhash_lock released |
336 | * upon function exit. | 339 | * upon function exit. |
337 | */ | 340 | */ |
338 | static inline void free_user(struct user_struct *up, unsigned long flags) | 341 | static void free_user(struct user_struct *up, unsigned long flags) |
339 | { | 342 | { |
340 | uid_hash_remove(up); | 343 | uid_hash_remove(up); |
341 | spin_unlock_irqrestore(&uidhash_lock, flags); | 344 | spin_unlock_irqrestore(&uidhash_lock, flags); |
342 | sched_destroy_user(up); | 345 | sched_destroy_user(up); |
343 | key_put(up->uid_keyring); | 346 | key_put(up->uid_keyring); |
344 | key_put(up->session_keyring); | 347 | key_put(up->session_keyring); |
348 | put_user_ns(up->user_ns); | ||
345 | kmem_cache_free(uid_cachep, up); | 349 | kmem_cache_free(uid_cachep, up); |
346 | } | 350 | } |
347 | 351 | ||
@@ -357,7 +361,7 @@ struct user_struct *find_user(uid_t uid) | |||
357 | { | 361 | { |
358 | struct user_struct *ret; | 362 | struct user_struct *ret; |
359 | unsigned long flags; | 363 | unsigned long flags; |
360 | struct user_namespace *ns = current->nsproxy->user_ns; | 364 | struct user_namespace *ns = current_user()->user_ns; |
361 | 365 | ||
362 | spin_lock_irqsave(&uidhash_lock, flags); | 366 | spin_lock_irqsave(&uidhash_lock, flags); |
363 | ret = uid_hash_find(uid, uidhashentry(ns, uid)); | 367 | ret = uid_hash_find(uid, uidhashentry(ns, uid)); |
@@ -404,6 +408,8 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid) | |||
404 | if (sched_create_user(new) < 0) | 408 | if (sched_create_user(new) < 0) |
405 | goto out_free_user; | 409 | goto out_free_user; |
406 | 410 | ||
411 | new->user_ns = get_user_ns(ns); | ||
412 | |||
407 | if (uids_user_create(new)) | 413 | if (uids_user_create(new)) |
408 | goto out_destoy_sched; | 414 | goto out_destoy_sched; |
409 | 415 | ||
@@ -427,7 +433,6 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid) | |||
427 | up = new; | 433 | up = new; |
428 | } | 434 | } |
429 | spin_unlock_irq(&uidhash_lock); | 435 | spin_unlock_irq(&uidhash_lock); |
430 | |||
431 | } | 436 | } |
432 | 437 | ||
433 | uids_mutex_unlock(); | 438 | uids_mutex_unlock(); |
@@ -436,6 +441,7 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid) | |||
436 | 441 | ||
437 | out_destoy_sched: | 442 | out_destoy_sched: |
438 | sched_destroy_user(new); | 443 | sched_destroy_user(new); |
444 | put_user_ns(new->user_ns); | ||
439 | out_free_user: | 445 | out_free_user: |
440 | kmem_cache_free(uid_cachep, new); | 446 | kmem_cache_free(uid_cachep, new); |
441 | out_unlock: | 447 | out_unlock: |
@@ -443,33 +449,6 @@ out_unlock: | |||
443 | return NULL; | 449 | return NULL; |
444 | } | 450 | } |
445 | 451 | ||
446 | #ifdef CONFIG_USER_NS | ||
447 | void release_uids(struct user_namespace *ns) | ||
448 | { | ||
449 | int i; | ||
450 | unsigned long flags; | ||
451 | struct hlist_head *head; | ||
452 | struct hlist_node *nd; | ||
453 | |||
454 | spin_lock_irqsave(&uidhash_lock, flags); | ||
455 | /* | ||
456 | * collapse the chains so that the user_struct-s will | ||
457 | * be still alive, but not in hashes. subsequent free_uid() | ||
458 | * will free them. | ||
459 | */ | ||
460 | for (i = 0; i < UIDHASH_SZ; i++) { | ||
461 | head = ns->uidhash_table + i; | ||
462 | while (!hlist_empty(head)) { | ||
463 | nd = head->first; | ||
464 | hlist_del_init(nd); | ||
465 | } | ||
466 | } | ||
467 | spin_unlock_irqrestore(&uidhash_lock, flags); | ||
468 | |||
469 | free_uid(ns->root_user); | ||
470 | } | ||
471 | #endif | ||
472 | |||
473 | static int __init uid_cache_init(void) | 452 | static int __init uid_cache_init(void) |
474 | { | 453 | { |
475 | int n; | 454 | int n; |