Commit 6209049e authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull ucounts fix from Eric Biederman:
 "Fix a subtle locking versus reference counting bug in the ucount
  changes, found by syzbot"

* 'for-v5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace:
  ucounts: Fix race condition between alloc_ucounts and put_ucounts
parents 3c3e9027 345daff2
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -160,6 +160,7 @@ struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid)
{
	struct hlist_head *hashent = ucounts_hashentry(ns, uid);
	struct ucounts *ucounts, *new;
	long overflow;

	spin_lock_irq(&ucounts_lock);
	ucounts = find_ucounts(ns, uid, hashent);
@@ -184,8 +185,12 @@ struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid)
			return new;
		}
	}
	overflow = atomic_add_negative(1, &ucounts->count);
	spin_unlock_irq(&ucounts_lock);
	ucounts = get_ucounts(ucounts);
	if (overflow) {
		put_ucounts(ucounts);
		return NULL;
	}
	return ucounts;
}

@@ -193,8 +198,7 @@ void put_ucounts(struct ucounts *ucounts)
{
	unsigned long flags;

	if (atomic_dec_and_test(&ucounts->count)) {
		spin_lock_irqsave(&ucounts_lock, flags);
	if (atomic_dec_and_lock_irqsave(&ucounts->count, &ucounts_lock, flags)) {
		hlist_del_init(&ucounts->node);
		spin_unlock_irqrestore(&ucounts_lock, flags);
		kfree(ucounts);