aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/sched.h1
-rw-r--r--kernel/user.c26
-rw-r--r--kernel/user_namespace.c2
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}
1473extern void free_uid(struct user_struct *); 1473extern void free_uid(struct user_struct *);
1474extern void switch_uid(struct user_struct *); 1474extern void switch_uid(struct user_struct *);
1475extern 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
63static inline void uid_hash_remove(struct user_struct *up) 63static 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
68static inline struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent) 68static 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
202void 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
203static int __init uid_cache_init(void) 227static 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