mirror of
https://github.com/adulau/aha.git
synced 2024-12-26 18:56:14 +00:00
Fix recursive lock in free_uid()/free_user_ns()
free_uid() and free_user_ns() are corecursive when CONFIG_USER_SCHED=n, but free_user_ns() is called from free_uid() by way of uid_hash_remove(), which requires uidhash_lock to be held. free_user_ns() then calls free_uid() to complete the destruction. Fix this by deferring the destruction of the user_namespace. Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: Serge Hallyn <serue@us.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
8ca2f156b0
commit
5170836679
2 changed files with 18 additions and 4 deletions
|
@ -13,6 +13,7 @@ struct user_namespace {
|
||||||
struct kref kref;
|
struct kref kref;
|
||||||
struct hlist_head uidhash_table[UIDHASH_SZ];
|
struct hlist_head uidhash_table[UIDHASH_SZ];
|
||||||
struct user_struct *creator;
|
struct user_struct *creator;
|
||||||
|
struct work_struct destroyer;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct user_namespace init_user_ns;
|
extern struct user_namespace init_user_ns;
|
||||||
|
|
|
@ -60,12 +60,25 @@ int create_user_ns(struct cred *new)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_user_ns(struct kref *kref)
|
/*
|
||||||
|
* Deferred destructor for a user namespace. This is required because
|
||||||
|
* free_user_ns() may be called with uidhash_lock held, but we need to call
|
||||||
|
* back to free_uid() which will want to take the lock again.
|
||||||
|
*/
|
||||||
|
static void free_user_ns_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct user_namespace *ns;
|
struct user_namespace *ns =
|
||||||
|
container_of(work, struct user_namespace, destroyer);
|
||||||
ns = container_of(kref, struct user_namespace, kref);
|
|
||||||
free_uid(ns->creator);
|
free_uid(ns->creator);
|
||||||
kfree(ns);
|
kfree(ns);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void free_user_ns(struct kref *kref)
|
||||||
|
{
|
||||||
|
struct user_namespace *ns =
|
||||||
|
container_of(kref, struct user_namespace, kref);
|
||||||
|
|
||||||
|
INIT_WORK(&ns->destroyer, free_user_ns_work);
|
||||||
|
schedule_work(&ns->destroyer);
|
||||||
|
}
|
||||||
EXPORT_SYMBOL(free_user_ns);
|
EXPORT_SYMBOL(free_user_ns);
|
||||||
|
|
Loading…
Reference in a new issue