Skip to content

Commit

Permalink
Fix recursive lock in free_uid()/free_user_ns()
Browse files Browse the repository at this point in the history
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 <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
dhowells authored and torvalds committed Feb 28, 2009
1 parent 8ca2f15 commit 5170836
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 4 deletions.
1 change: 1 addition & 0 deletions include/linux/user_namespace.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ struct user_namespace {
struct kref kref;
struct hlist_head uidhash_table[UIDHASH_SZ];
struct user_struct *creator;
struct work_struct destroyer;
};

extern struct user_namespace init_user_ns;
Expand Down
21 changes: 17 additions & 4 deletions kernel/user_namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,25 @@ int create_user_ns(struct cred *new)
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;

ns = container_of(kref, struct user_namespace, kref);
struct user_namespace *ns =
container_of(work, struct user_namespace, destroyer);
free_uid(ns->creator);
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);

0 comments on commit 5170836

Please sign in to comment.