aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2016-07-30 14:53:37 -0400
committerEric W. Biederman <ebiederm@xmission.com>2016-08-08 10:17:18 -0400
commitb032132c3c218f4a09e9499b3674299a752581c6 (patch)
tree053a27f83f9bf00638197f451f49117cfe110fea
parent13bcc6a2853435bb5dad368bcbaa9d2a5b9c0ac4 (diff)
userns: Free user namespaces in process context
Add the necessary boiler plate to move freeing of user namespaces into work queue and thus into process context where things can sleep. This is a necessary precursor to per user namespace sysctls. Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
-rw-r--r--include/linux/user_namespace.h5
-rw-r--r--kernel/user_namespace.c14
2 files changed, 14 insertions, 5 deletions
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index 9217169c64cb..4e79b3c64dee 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -39,6 +39,7 @@ struct user_namespace {
39 struct key *persistent_keyring_register; 39 struct key *persistent_keyring_register;
40 struct rw_semaphore persistent_keyring_register_sem; 40 struct rw_semaphore persistent_keyring_register_sem;
41#endif 41#endif
42 struct work_struct work;
42}; 43};
43 44
44extern struct user_namespace init_user_ns; 45extern struct user_namespace init_user_ns;
@@ -54,12 +55,12 @@ static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
54 55
55extern int create_user_ns(struct cred *new); 56extern int create_user_ns(struct cred *new);
56extern int unshare_userns(unsigned long unshare_flags, struct cred **new_cred); 57extern int unshare_userns(unsigned long unshare_flags, struct cred **new_cred);
57extern void free_user_ns(struct user_namespace *ns); 58extern void __put_user_ns(struct user_namespace *ns);
58 59
59static inline void put_user_ns(struct user_namespace *ns) 60static inline void put_user_ns(struct user_namespace *ns)
60{ 61{
61 if (ns && atomic_dec_and_test(&ns->count)) 62 if (ns && atomic_dec_and_test(&ns->count))
62 free_user_ns(ns); 63 __put_user_ns(ns);
63} 64}
64 65
65struct seq_operations; 66struct seq_operations;
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 68f594212759..5247cdb24e62 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -29,6 +29,7 @@ static DEFINE_MUTEX(userns_state_mutex);
29static bool new_idmap_permitted(const struct file *file, 29static bool new_idmap_permitted(const struct file *file,
30 struct user_namespace *ns, int cap_setid, 30 struct user_namespace *ns, int cap_setid,
31 struct uid_gid_map *map); 31 struct uid_gid_map *map);
32static void free_user_ns(struct work_struct *work);
32 33
33static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns) 34static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
34{ 35{
@@ -101,6 +102,7 @@ int create_user_ns(struct cred *new)
101 ns->level = parent_ns->level + 1; 102 ns->level = parent_ns->level + 1;
102 ns->owner = owner; 103 ns->owner = owner;
103 ns->group = group; 104 ns->group = group;
105 INIT_WORK(&ns->work, free_user_ns);
104 106
105 /* Inherit USERNS_SETGROUPS_ALLOWED from our parent */ 107 /* Inherit USERNS_SETGROUPS_ALLOWED from our parent */
106 mutex_lock(&userns_state_mutex); 108 mutex_lock(&userns_state_mutex);
@@ -135,9 +137,10 @@ int unshare_userns(unsigned long unshare_flags, struct cred **new_cred)
135 return err; 137 return err;
136} 138}
137 139
138void free_user_ns(struct user_namespace *ns) 140static void free_user_ns(struct work_struct *work)
139{ 141{
140 struct user_namespace *parent; 142 struct user_namespace *parent, *ns =
143 container_of(work, struct user_namespace, work);
141 144
142 do { 145 do {
143 parent = ns->parent; 146 parent = ns->parent;
@@ -149,7 +152,12 @@ void free_user_ns(struct user_namespace *ns)
149 ns = parent; 152 ns = parent;
150 } while (atomic_dec_and_test(&parent->count)); 153 } while (atomic_dec_and_test(&parent->count));
151} 154}
152EXPORT_SYMBOL(free_user_ns); 155
156void __put_user_ns(struct user_namespace *ns)
157{
158 schedule_work(&ns->work);
159}
160EXPORT_SYMBOL(__put_user_ns);
153 161
154static u32 map_id_range_down(struct uid_gid_map *map, u32 id, u32 count) 162static u32 map_id_range_down(struct uid_gid_map *map, u32 id, u32 count)
155{ 163{