diff options
Diffstat (limited to 'kernel/user.c')
-rw-r--r-- | kernel/user.c | 35 |
1 files changed, 26 insertions, 9 deletions
diff --git a/kernel/user.c b/kernel/user.c index d8b332c3ae3a..850e0ba41c1e 100644 --- a/kernel/user.c +++ b/kernel/user.c | |||
@@ -72,6 +72,7 @@ static void uid_hash_insert(struct user_struct *up, struct hlist_head *hashent) | |||
72 | static void uid_hash_remove(struct user_struct *up) | 72 | static void uid_hash_remove(struct user_struct *up) |
73 | { | 73 | { |
74 | hlist_del_init(&up->uidhash_node); | 74 | hlist_del_init(&up->uidhash_node); |
75 | put_user_ns(up->user_ns); | ||
75 | } | 76 | } |
76 | 77 | ||
77 | static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent) | 78 | static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent) |
@@ -285,14 +286,12 @@ int __init uids_sysfs_init(void) | |||
285 | /* work function to remove sysfs directory for a user and free up | 286 | /* work function to remove sysfs directory for a user and free up |
286 | * corresponding structures. | 287 | * corresponding structures. |
287 | */ | 288 | */ |
288 | static void remove_user_sysfs_dir(struct work_struct *w) | 289 | static void cleanup_user_struct(struct work_struct *w) |
289 | { | 290 | { |
290 | struct user_struct *up = container_of(w, struct user_struct, work); | 291 | struct user_struct *up = container_of(w, struct user_struct, work); |
291 | unsigned long flags; | 292 | unsigned long flags; |
292 | int remove_user = 0; | 293 | int remove_user = 0; |
293 | 294 | ||
294 | if (up->user_ns != &init_user_ns) | ||
295 | return; | ||
296 | /* Make uid_hash_remove() + sysfs_remove_file() + kobject_del() | 295 | /* Make uid_hash_remove() + sysfs_remove_file() + kobject_del() |
297 | * atomic. | 296 | * atomic. |
298 | */ | 297 | */ |
@@ -311,9 +310,11 @@ static void remove_user_sysfs_dir(struct work_struct *w) | |||
311 | if (!remove_user) | 310 | if (!remove_user) |
312 | goto done; | 311 | goto done; |
313 | 312 | ||
314 | kobject_uevent(&up->kobj, KOBJ_REMOVE); | 313 | if (up->user_ns == &init_user_ns) { |
315 | kobject_del(&up->kobj); | 314 | kobject_uevent(&up->kobj, KOBJ_REMOVE); |
316 | kobject_put(&up->kobj); | 315 | kobject_del(&up->kobj); |
316 | kobject_put(&up->kobj); | ||
317 | } | ||
317 | 318 | ||
318 | sched_destroy_user(up); | 319 | sched_destroy_user(up); |
319 | key_put(up->uid_keyring); | 320 | key_put(up->uid_keyring); |
@@ -334,8 +335,7 @@ static void free_user(struct user_struct *up, unsigned long flags) | |||
334 | atomic_inc(&up->__count); | 335 | atomic_inc(&up->__count); |
335 | spin_unlock_irqrestore(&uidhash_lock, flags); | 336 | spin_unlock_irqrestore(&uidhash_lock, flags); |
336 | 337 | ||
337 | put_user_ns(up->user_ns); | 338 | INIT_WORK(&up->work, cleanup_user_struct); |
338 | INIT_WORK(&up->work, remove_user_sysfs_dir); | ||
339 | schedule_work(&up->work); | 339 | schedule_work(&up->work); |
340 | } | 340 | } |
341 | 341 | ||
@@ -357,12 +357,29 @@ static void free_user(struct user_struct *up, unsigned long flags) | |||
357 | sched_destroy_user(up); | 357 | sched_destroy_user(up); |
358 | key_put(up->uid_keyring); | 358 | key_put(up->uid_keyring); |
359 | key_put(up->session_keyring); | 359 | key_put(up->session_keyring); |
360 | put_user_ns(up->user_ns); | ||
361 | kmem_cache_free(uid_cachep, up); | 360 | kmem_cache_free(uid_cachep, up); |
362 | } | 361 | } |
363 | 362 | ||
364 | #endif | 363 | #endif |
365 | 364 | ||
365 | #if defined(CONFIG_RT_GROUP_SCHED) && defined(CONFIG_USER_SCHED) | ||
366 | /* | ||
367 | * We need to check if a setuid can take place. This function should be called | ||
368 | * before successfully completing the setuid. | ||
369 | */ | ||
370 | int task_can_switch_user(struct user_struct *up, struct task_struct *tsk) | ||
371 | { | ||
372 | |||
373 | return sched_rt_can_attach(up->tg, tsk); | ||
374 | |||
375 | } | ||
376 | #else | ||
377 | int task_can_switch_user(struct user_struct *up, struct task_struct *tsk) | ||
378 | { | ||
379 | return 1; | ||
380 | } | ||
381 | #endif | ||
382 | |||
366 | /* | 383 | /* |
367 | * Locate the user_struct for the passed UID. If found, take a ref on it. The | 384 | * Locate the user_struct for the passed UID. If found, take a ref on it. The |
368 | * caller must undo that ref with free_uid(). | 385 | * caller must undo that ref with free_uid(). |