diff options
-rw-r--r-- | include/linux/sched.h | 1 | ||||
-rw-r--r-- | kernel/user.c | 26 | ||||
-rw-r--r-- | kernel/user_namespace.c | 2 |
3 files changed, 27 insertions, 2 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h index 6239bc2c2baa..5445eaec6908 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -1472,6 +1472,7 @@ static inline struct user_struct *get_uid(struct user_struct *u) | |||
1472 | } | 1472 | } |
1473 | extern void free_uid(struct user_struct *); | 1473 | extern void free_uid(struct user_struct *); |
1474 | extern void switch_uid(struct user_struct *); | 1474 | extern void switch_uid(struct user_struct *); |
1475 | extern void release_uids(struct user_namespace *ns); | ||
1475 | 1476 | ||
1476 | #include <asm/current.h> | 1477 | #include <asm/current.h> |
1477 | 1478 | ||
diff --git a/kernel/user.c b/kernel/user.c index add57c7e4c07..9ca2848fc356 100644 --- a/kernel/user.c +++ b/kernel/user.c | |||
@@ -62,7 +62,7 @@ static inline void uid_hash_insert(struct user_struct *up, struct hlist_head *ha | |||
62 | 62 | ||
63 | static inline void uid_hash_remove(struct user_struct *up) | 63 | static inline void uid_hash_remove(struct user_struct *up) |
64 | { | 64 | { |
65 | hlist_del(&up->uidhash_node); | 65 | hlist_del_init(&up->uidhash_node); |
66 | } | 66 | } |
67 | 67 | ||
68 | static inline struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent) | 68 | static inline struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent) |
@@ -199,6 +199,30 @@ void switch_uid(struct user_struct *new_user) | |||
199 | suid_keys(current); | 199 | suid_keys(current); |
200 | } | 200 | } |
201 | 201 | ||
202 | void release_uids(struct user_namespace *ns) | ||
203 | { | ||
204 | int i; | ||
205 | unsigned long flags; | ||
206 | struct hlist_head *head; | ||
207 | struct hlist_node *nd; | ||
208 | |||
209 | spin_lock_irqsave(&uidhash_lock, flags); | ||
210 | /* | ||
211 | * collapse the chains so that the user_struct-s will | ||
212 | * be still alive, but not in hashes. subsequent free_uid() | ||
213 | * will free them. | ||
214 | */ | ||
215 | for (i = 0; i < UIDHASH_SZ; i++) { | ||
216 | head = ns->uidhash_table + i; | ||
217 | while (!hlist_empty(head)) { | ||
218 | nd = head->first; | ||
219 | hlist_del_init(nd); | ||
220 | } | ||
221 | } | ||
222 | spin_unlock_irqrestore(&uidhash_lock, flags); | ||
223 | |||
224 | free_uid(ns->root_user); | ||
225 | } | ||
202 | 226 | ||
203 | static int __init uid_cache_init(void) | 227 | static int __init uid_cache_init(void) |
204 | { | 228 | { |
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index e7ba1bf8457c..7af90fc4f0fd 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c | |||
@@ -81,7 +81,7 @@ void free_user_ns(struct kref *kref) | |||
81 | struct user_namespace *ns; | 81 | struct user_namespace *ns; |
82 | 82 | ||
83 | ns = container_of(kref, struct user_namespace, kref); | 83 | ns = container_of(kref, struct user_namespace, kref); |
84 | free_uid(ns->root_user); | 84 | release_uids(ns); |
85 | kfree(ns); | 85 | kfree(ns); |
86 | } | 86 | } |
87 | 87 | ||