Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 51708366 authored by David Howells's avatar David Howells Committed by Linus Torvalds
Browse files

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: default avatarDavid Howells <dhowells@redhat.com>
Acked-by: default avatarSerge Hallyn <serue@us.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 8ca2f156
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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;
+17 −4
Original line number Diff line number Diff line
@@ -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);