Commit 7fe2bc1b authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'ucount-rlimit-fixes-for-v5.16' of...

Merge branch 'ucount-rlimit-fixes-for-v5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace

Pull ucount fix from Eric Biederman:
 "This fixes a silly logic bug in the ucount rlimits code, where it was
  comparing against the wrong limit"

* 'ucount-rlimit-fixes-for-v5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace:
  ucounts: Fix rlimit max values check
parents 76657eae 59ec7157
Loading
Loading
Loading
Loading
+9 −6
Original line number Original line Diff line number Diff line
@@ -264,15 +264,16 @@ void dec_ucount(struct ucounts *ucounts, enum ucount_type type)
long inc_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v)
long inc_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v)
{
{
	struct ucounts *iter;
	struct ucounts *iter;
	long max = LONG_MAX;
	long ret = 0;
	long ret = 0;


	for (iter = ucounts; iter; iter = iter->ns->ucounts) {
	for (iter = ucounts; iter; iter = iter->ns->ucounts) {
		long max = READ_ONCE(iter->ns->ucount_max[type]);
		long new = atomic_long_add_return(v, &iter->ucount[type]);
		long new = atomic_long_add_return(v, &iter->ucount[type]);
		if (new < 0 || new > max)
		if (new < 0 || new > max)
			ret = LONG_MAX;
			ret = LONG_MAX;
		else if (iter == ucounts)
		else if (iter == ucounts)
			ret = new;
			ret = new;
		max = READ_ONCE(iter->ns->ucount_max[type]);
	}
	}
	return ret;
	return ret;
}
}
@@ -312,15 +313,16 @@ long inc_rlimit_get_ucounts(struct ucounts *ucounts, enum ucount_type type)
{
{
	/* Caller must hold a reference to ucounts */
	/* Caller must hold a reference to ucounts */
	struct ucounts *iter;
	struct ucounts *iter;
	long max = LONG_MAX;
	long dec, ret = 0;
	long dec, ret = 0;


	for (iter = ucounts; iter; iter = iter->ns->ucounts) {
	for (iter = ucounts; iter; iter = iter->ns->ucounts) {
		long max = READ_ONCE(iter->ns->ucount_max[type]);
		long new = atomic_long_add_return(1, &iter->ucount[type]);
		long new = atomic_long_add_return(1, &iter->ucount[type]);
		if (new < 0 || new > max)
		if (new < 0 || new > max)
			goto unwind;
			goto unwind;
		if (iter == ucounts)
		if (iter == ucounts)
			ret = new;
			ret = new;
		max = READ_ONCE(iter->ns->ucount_max[type]);
		/*
		/*
		 * Grab an extra ucount reference for the caller when
		 * Grab an extra ucount reference for the caller when
		 * the rlimit count was previously 0.
		 * the rlimit count was previously 0.
@@ -339,15 +341,16 @@ long inc_rlimit_get_ucounts(struct ucounts *ucounts, enum ucount_type type)
	return 0;
	return 0;
}
}


bool is_ucounts_overlimit(struct ucounts *ucounts, enum ucount_type type, unsigned long max)
bool is_ucounts_overlimit(struct ucounts *ucounts, enum ucount_type type, unsigned long rlimit)
{
{
	struct ucounts *iter;
	struct ucounts *iter;
	if (get_ucounts_value(ucounts, type) > max)
	long max = rlimit;
		return true;
	if (rlimit > LONG_MAX)
		max = LONG_MAX;
	for (iter = ucounts; iter; iter = iter->ns->ucounts) {
	for (iter = ucounts; iter; iter = iter->ns->ucounts) {
		max = READ_ONCE(iter->ns->ucount_max[type]);
		if (get_ucounts_value(iter, type) > max)
		if (get_ucounts_value(iter, type) > max)
			return true;
			return true;
		max = READ_ONCE(iter->ns->ucount_max[type]);
	}
	}
	return false;
	return false;
}
}