From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 893C73845A9; Wed, 7 Oct 2026 22:00:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791410409; cv=none; b=rSFOPmpeRHo/KLvN59p31a1Lvt3kwvFT4TN8ZJoCOv0UEYlmfUwwcZx/ONqhol2guhY/SYb5XGczyS4re+i9s0tIM5+SSP0LSRQ5UmAV6eDnB0rW4MJvIx8htR2LS/Hf7M04qz9YQaK0+yqv8e0ehXtBcEtJLqHPrdloqQDwb8s= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791410409; c=relaxed/simple; bh=YD/W6exh0vaVkcMG7NX3aU2BBDY0x89/ll4+tWiN3gg=; h=Date:From:To:Cc:Subject:Message-Id:In-Reply-To:References: Mime-Version:Content-Type; b=T5ZFE6v2kklakhO6M7DQSMay4990lAtagkHAO+iBP4xb/pf3KpBGPFVqZth5NFf2KzuGyjDxO265sjHYf27RgNxYGxQljU8bOrmihf5FDdwl1d7qbSHTpFPLuq0nonQ3f9aTRZQr441LQgHDradgOcXtAunNllACA8BMT6ipXzM= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux-foundation.org header.i=@linux-foundation.org header.b=FRGuoVCN; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux-foundation.org header.i=@linux-foundation.org header.b="FRGuoVCN" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DE0751F00893; Wed, 7 Oct 2026 22:00:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux-foundation.org; s=korg; t=1791410408; bh=WVLhQGPSFdOEw9eZATSNwWpkoWmnuQn/J8kRhpK/kts=; h=Date:From:To:Cc:Subject:In-Reply-To:References; b=FRGuoVCNMJ+wGLAMJK2SAOlkhUF6wuQ0igJPhMxC3WCmjgnwcNVi3JeWSdOxY4rjm z1x6s8oivqlTGapFwRGY9PgH/PUnp/FyMovTaOcVPIl52FC+mYGEMhQGkVwml8YfhM QQzP51AItX6d7m4e7uHNgxMBEq6ECAQzCvcQxAg4= Date: Wed, 7 Oct 2026 15:00:07 -0700 From: Andrew Morton To: Armaan Sandhu Cc: Andy Shevchenko , linux-kernel@vger.kernel.org, stable@vger.kernel.org, lzhan011 Subject: Re: [PATCH] lib/cmdline: fix get_options() count and overflow with large ranges Message-Id: <20261007150007.c7c6f2a4e41fd9f950c8427c@linux-foundation.org> In-Reply-To: <20261005213945.359905-1-armaan.sandhu0504@gmail.com> References: <20261005213945.359905-1-armaan.sandhu0504@gmail.com> X-Mailer: Sylpheed 3.8.0beta1 (GTK+ 2.24.33; x86_64-pc-linux-gnu) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit On Mon, 5 Oct 2026 17:39:45 -0400 Armaan Sandhu wrote: > get_range() stops writing once the array is full, but get_options() > still advances its index by the whole range. So "1-100" parsed into > four ints reports 99 numbers, and a range like "0-2147483647" wraps > the index negative and writes outside the array. > > Stop once a range fills the array, bail out in validation mode before > the count overflows, and saturate the range length in get_range(). > Add KUnit cases; without the fix "0-2147483647" panics the test kernel. > > Only root can supply this input, so this is a robustness fix. > > Fixes: 22f2e2801799 ("[PATCH] get_options to allow a hypenated range for isolcpus") > Cc: stable@vger.kernel.org > Signed-off-by: Armaan Sandhu I've received two fixes for the same 20 year old bug with an hour (https://lore.kernel.org/20261005202412.3460441-1-lzsx618@gmail.com). How did that happen? > lib/cmdline.c | 13 ++++++++++++- > lib/tests/cmdline_kunit.c | 38 ++++++++++++++++++++++++++++++++++++++ > 2 files changed, 50 insertions(+), 1 deletion(-) The kunit changes appear to be identical. Which fix is best? > diff --git a/lib/cmdline.c b/lib/cmdline.c > index 16cce6621cec..40b98d943a9a 100644 > --- a/lib/cmdline.c > +++ b/lib/cmdline.c > @@ -11,6 +11,7 @@ > > #include > #include > +#include > #include > #include > > @@ -26,7 +27,9 @@ static int get_range(char **str, int *pint, int n) > > (*str)++; > upper_range = simple_strtol((*str), NULL, 0); > - inc_counter = upper_range - *pint; > + /* Keep the sign of the result when the difference doesn't fit */ > + if (check_sub_overflow(upper_range, *pint, &inc_counter)) > + inc_counter = upper_range < *pint ? -1 : INT_MAX; > for (x = *pint; n && x < upper_range; x++, n--) > *pint++ = x; > return inc_counter; > @@ -122,6 +125,14 @@ char *get_options(const char *str, int nints, int *ints) > range_nums = get_range((char **)&str, pint, n); > if (range_nums < 0) > break; > + /* The range didn't fit, so the array is full */ > + if (!validate && range_nums > n) { > + i = nints; > + break; > + } > + /* Leave room for the upper number of the range */ > + if (range_nums >= INT_MAX - i) > + break; > /* > * Decrement the result by one to leave out the > * last number in the range. The next iteration > diff --git a/lib/tests/cmdline_kunit.c b/lib/tests/cmdline_kunit.c > index 3f61ff8d3178..584fcb2c0e44 100644 > --- a/lib/tests/cmdline_kunit.c > +++ b/lib/tests/cmdline_kunit.c > @@ -140,6 +140,43 @@ static void cmdline_test_range(struct kunit *test) > } while (++i < ARRAY_SIZE(cmdline_test_range_strings)); > } > > +static const struct { > + const char *in; > + int parsed[4]; > + int validated; > +} cmdline_test_range_overflow_cases[] = { > + { "1-100", { 3, 1, 2, 3, }, 100, }, > + { "1,5-100,7", { 3, 1, 5, 6, }, 98, }, > + { "1-2147483646", { 3, 1, 2, 3, }, 2147483646, }, > + { "0-2147483647", { 3, 0, 1, 2, }, 0, }, > + { "-5-2147483647", { 3, -5, -4, -3, }, 0, }, > + { "2147483647--5", { 0, 2147483647, }, 0, }, > +}; > + > +static void cmdline_test_range_overflow(struct kunit *test) > +{ > + unsigned int i, j; > + > + for (i = 0; i < ARRAY_SIZE(cmdline_test_range_overflow_cases); i++) { > + const char *in = cmdline_test_range_overflow_cases[i].in; > + const int *e = cmdline_test_range_overflow_cases[i].parsed; > + /* Two guard elements past the array handed to get_options() */ > + int r[ARRAY_SIZE(cmdline_test_range_overflow_cases[0].parsed) + 2]; > + int n; > + > + memset(r, 0, sizeof(r)); > + get_options(in, ARRAY_SIZE(r) - 2, r); > + for (j = 0; j < ARRAY_SIZE(r) - 2; j++) > + KUNIT_EXPECT_EQ_MSG(test, r[j], e[j], "Pattern: %s at %u", in, j); > + for (; j < ARRAY_SIZE(r); j++) > + KUNIT_EXPECT_EQ_MSG(test, r[j], 0, "Pattern: %s out of bound at %u", in, j); > + > + get_options(in, 0, &n); > + KUNIT_EXPECT_EQ_MSG(test, n, cmdline_test_range_overflow_cases[i].validated, > + "Pattern: %s (validated)", in); > + } > +} > + > static void cmdline_test_next_arg_quoted_value(struct kunit *test) > { > char in[] = "foo=\"bar baz\" qux=1"; > @@ -258,6 +295,7 @@ static struct kunit_case cmdline_test_cases[] = { > KUNIT_CASE(cmdline_test_lead_int), > KUNIT_CASE(cmdline_test_tail_int), > KUNIT_CASE(cmdline_test_range), > + KUNIT_CASE(cmdline_test_range_overflow), > KUNIT_CASE(cmdline_test_next_arg_quoted_value), > KUNIT_CASE(cmdline_test_next_arg_bare_quote_regression), > KUNIT_CASE(cmdline_test_next_arg_mixed_tokens), > -- > 2.55.0