Commit b032132c authored by Eric W. Biederman's avatar Eric W. Biederman

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: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
parent 13bcc6a2
...@@ -39,6 +39,7 @@ struct user_namespace { ...@@ -39,6 +39,7 @@ struct user_namespace {
struct key *persistent_keyring_register; struct key *persistent_keyring_register;
struct rw_semaphore persistent_keyring_register_sem; struct rw_semaphore persistent_keyring_register_sem;
#endif #endif
struct work_struct work;
}; };
extern struct user_namespace init_user_ns; extern struct user_namespace init_user_ns;
...@@ -54,12 +55,12 @@ static inline struct user_namespace *get_user_ns(struct user_namespace *ns) ...@@ -54,12 +55,12 @@ static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
extern int create_user_ns(struct cred *new); extern int create_user_ns(struct cred *new);
extern int unshare_userns(unsigned long unshare_flags, struct cred **new_cred); extern int unshare_userns(unsigned long unshare_flags, struct cred **new_cred);
extern void free_user_ns(struct user_namespace *ns); extern void __put_user_ns(struct user_namespace *ns);
static inline void put_user_ns(struct user_namespace *ns) static inline void put_user_ns(struct user_namespace *ns)
{ {
if (ns && atomic_dec_and_test(&ns->count)) if (ns && atomic_dec_and_test(&ns->count))
free_user_ns(ns); __put_user_ns(ns);
} }
struct seq_operations; struct seq_operations;
......
...@@ -29,6 +29,7 @@ static DEFINE_MUTEX(userns_state_mutex); ...@@ -29,6 +29,7 @@ static DEFINE_MUTEX(userns_state_mutex);
static bool new_idmap_permitted(const struct file *file, static bool new_idmap_permitted(const struct file *file,
struct user_namespace *ns, int cap_setid, struct user_namespace *ns, int cap_setid,
struct uid_gid_map *map); struct uid_gid_map *map);
static void free_user_ns(struct work_struct *work);
static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns) static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
{ {
...@@ -101,6 +102,7 @@ int create_user_ns(struct cred *new) ...@@ -101,6 +102,7 @@ int create_user_ns(struct cred *new)
ns->level = parent_ns->level + 1; ns->level = parent_ns->level + 1;
ns->owner = owner; ns->owner = owner;
ns->group = group; ns->group = group;
INIT_WORK(&ns->work, free_user_ns);
/* Inherit USERNS_SETGROUPS_ALLOWED from our parent */ /* Inherit USERNS_SETGROUPS_ALLOWED from our parent */
mutex_lock(&userns_state_mutex); mutex_lock(&userns_state_mutex);
...@@ -135,9 +137,10 @@ int unshare_userns(unsigned long unshare_flags, struct cred **new_cred) ...@@ -135,9 +137,10 @@ int unshare_userns(unsigned long unshare_flags, struct cred **new_cred)
return err; return err;
} }
void free_user_ns(struct user_namespace *ns) static void free_user_ns(struct work_struct *work)
{ {
struct user_namespace *parent; struct user_namespace *parent, *ns =
container_of(work, struct user_namespace, work);
do { do {
parent = ns->parent; parent = ns->parent;
...@@ -149,7 +152,12 @@ void free_user_ns(struct user_namespace *ns) ...@@ -149,7 +152,12 @@ void free_user_ns(struct user_namespace *ns)
ns = parent; ns = parent;
} while (atomic_dec_and_test(&parent->count)); } while (atomic_dec_and_test(&parent->count));
} }
EXPORT_SYMBOL(free_user_ns);
void __put_user_ns(struct user_namespace *ns)
{
schedule_work(&ns->work);
}
EXPORT_SYMBOL(__put_user_ns);
static u32 map_id_range_down(struct uid_gid_map *map, u32 id, u32 count) static u32 map_id_range_down(struct uid_gid_map *map, u32 id, u32 count)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment