[PATCH] lib: string_helpers: fix potential snprintf() output truncation

Bartosz Golaszewski posted 1 patch 1 month ago
lib/string_helpers.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
[PATCH] lib: string_helpers: fix potential snprintf() output truncation
Posted by Bartosz Golaszewski 1 month ago
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

The output of ".%03u" with the unsigned int in range [0, 4294966295] may
get truncated if the target buffer is not 12 bytes.

Fixes: 3c9f3681d0b4 ("[SCSI] lib: add generic helper to print sizes rounded to the correct SI range")
Cc: stable@vger.kernel.org
Reviewed-by: Andy Shevchenko <andy@kernel.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 lib/string_helpers.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/string_helpers.c b/lib/string_helpers.c
index 4f887aa62fa0..91fa37b5c510 100644
--- a/lib/string_helpers.c
+++ b/lib/string_helpers.c
@@ -57,7 +57,7 @@ int string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
 	static const unsigned int rounding[] = { 500, 50, 5 };
 	int i = 0, j;
 	u32 remainder = 0, sf_cap;
-	char tmp[8];
+	char tmp[12];
 	const char *unit;
 
 	tmp[0] = '\0';
-- 
2.43.0
Re: [PATCH] lib: string_helpers: fix potential snprintf() output truncation
Posted by Jiri Slaby 1 month ago
On 21. 10. 24, 12:04, Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> 
> The output of ".%03u" with the unsigned int in range [0, 4294966295] may
> get truncated if the target buffer is not 12 bytes.

Perhaps, if you elaborate on how 'remainder' can become > 999?

> Fixes: 3c9f3681d0b4 ("[SCSI] lib: add generic helper to print sizes rounded to the correct SI range")
> Cc: stable@vger.kernel.org
> Reviewed-by: Andy Shevchenko <andy@kernel.org>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> ---
>   lib/string_helpers.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/lib/string_helpers.c b/lib/string_helpers.c
> index 4f887aa62fa0..91fa37b5c510 100644
> --- a/lib/string_helpers.c
> +++ b/lib/string_helpers.c
> @@ -57,7 +57,7 @@ int string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
>   	static const unsigned int rounding[] = { 500, 50, 5 };
>   	int i = 0, j;
>   	u32 remainder = 0, sf_cap;
> -	char tmp[8];
> +	char tmp[12];
>   	const char *unit;
>   
>   	tmp[0] = '\0';

-- 
js
suse labs
Re: [PATCH] lib: string_helpers: fix potential snprintf() output truncation
Posted by Andy Shevchenko 1 month ago
On Tue, Oct 22, 2024 at 10:15 AM Jiri Slaby <jirislaby@kernel.org> wrote:
>
> On 21. 10. 24, 12:04, Bartosz Golaszewski wrote:
> > From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> >
> > The output of ".%03u" with the unsigned int in range [0, 4294966295] may
> > get truncated if the target buffer is not 12 bytes.
>
> Perhaps, if you elaborate on how 'remainder' can become > 999?

The problem here that we have a two-way road: on one hand we ought to
fix the bugs in the kernel, on the other hand the compiler warnings
(even false positives) better to be fixed as we don't know which
compiler gets it fixed, but now we have a problem with building with
`make W=1` for the default configurations (it prevents build due to
compilation errors), so this change is definitely is an improvement.

-- 
With Best Regards,
Andy Shevchenko
Re: [PATCH] lib: string_helpers: fix potential snprintf() output truncation
Posted by Rasmus Villemoes 1 month ago
On Tue, Oct 22 2024, Andy Shevchenko <andy.shevchenko@gmail.com> wrote:

> On Tue, Oct 22, 2024 at 10:15 AM Jiri Slaby <jirislaby@kernel.org> wrote:
>>
>> On 21. 10. 24, 12:04, Bartosz Golaszewski wrote:
>> > From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>> >
>> > The output of ".%03u" with the unsigned int in range [0, 4294966295] may
>> > get truncated if the target buffer is not 12 bytes.
>>
>> Perhaps, if you elaborate on how 'remainder' can become > 999?
>
> The problem here that we have a two-way road: on one hand we ought to
> fix the bugs in the kernel, on the other hand the compiler warnings
> (even false positives) better to be fixed as we don't know which
> compiler gets it fixed, but now we have a problem with building with
> `make W=1` for the default configurations (it prevents build due to
> compilation errors), so this change is definitely is an improvement.

Well, yes, kind of, and of course a 12 byte stack buffer doesn't hurt
more than an 8 byte one (i.e. not at all). However, it does feel rather
arbitrary.

Can't we fix the code to avoid the tmp buffer and do one less
snprintf()? Something like this entirely untested thing:

diff --git a/lib/string_helpers.c b/lib/string_helpers.c
index 9982344cca34..7aa592f9a494 100644
--- a/lib/string_helpers.c
+++ b/lib/string_helpers.c
@@ -50,13 +50,10 @@ void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
 		[STRING_UNITS_2] = 1024,
 	};
 	static const unsigned int rounding[] = { 500, 50, 5 };
-	int i = 0, j;
+	int i = 0, j = 0;
 	u32 remainder = 0, sf_cap;
-	char tmp[8];
 	const char *unit;
 
-	tmp[0] = '\0';
-
 	if (blk_size == 0)
 		size = 0;
 	if (size == 0)
@@ -115,19 +112,16 @@ void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
 		size += 1;
 	}
 
-	if (j) {
-		snprintf(tmp, sizeof(tmp), ".%03u", remainder);
-		tmp[j+1] = '\0';
-	}
-
  out:
 	if (i >= ARRAY_SIZE(units_2))
 		unit = "UNK";
 	else
 		unit = units_str[units][i];
 
-	snprintf(buf, len, "%u%s %s", (u32)size,
-		 tmp, unit);
+	if (j)
+		snprintf(buf, len, "%u.%03u %s", (u32)size, remainder, unit);
+	else
+		snprintf(buf, len, "%u %s", (u32)size, unit);
 }
 EXPORT_SYMBOL(string_get_size);
 
Rasmus
Re: [PATCH] lib: string_helpers: fix potential snprintf() output truncation
Posted by James Bottomley 1 month ago
On Tue, 2024-10-22 at 15:46 +0200, Rasmus Villemoes wrote:
[...]
> -       snprintf(buf, len, "%u%s %s", (u32)size,
> -                tmp, unit);
> +       if (j)
> +               snprintf(buf, len, "%u.%03u %s", (u32)size,
> remainder, unit);
> +       else
> +               snprintf(buf, len, "%u %s", (u32)size, unit);
>  }
>  EXPORT_SYMBOL(string_get_size);

Where are you getting this from?  The current statement you'd be
replacing is

	return snprintf(buf, len, "%u%s%s%s%s", (u32)size, tmp,
			(units & STRING_UNITS_NO_SPACE) ? "" : " ",
			unit,
			(units & STRING_UNITS_NO_BYTES) ? "" : "B");

The use of a tmp buffer prevents that having to be repeated.

If we had a way of specifying "ignore argument" I suppose we could
switch the format string on J and then only have a single statement.

Regards,

James

Re: [PATCH] lib: string_helpers: fix potential snprintf() output truncation
Posted by Bartosz Golaszewski 1 month ago
On Tue, Oct 22, 2024 at 9:15 AM Jiri Slaby <jirislaby@kernel.org> wrote:
>
> On 21. 10. 24, 12:04, Bartosz Golaszewski wrote:
> > From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> >
> > The output of ".%03u" with the unsigned int in range [0, 4294966295] may
> > get truncated if the target buffer is not 12 bytes.
>
> Perhaps, if you elaborate on how 'remainder' can become > 999?
>

Yeah, I guess it can't. Not sure what we do about such false
positives, do we have some common way to suppress them?

Bart
RE: [PATCH] lib: string_helpers: fix potential snprintf() output truncation
Posted by David Laight 1 month ago
From: Bartosz Golaszewski
> Sent: 22 October 2024 08:30
> 
> On Tue, Oct 22, 2024 at 9:15 AM Jiri Slaby <jirislaby@kernel.org> wrote:
> >
> > On 21. 10. 24, 12:04, Bartosz Golaszewski wrote:
> > > From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> > >
> > > The output of ".%03u" with the unsigned int in range [0, 4294966295] may
> > > get truncated if the target buffer is not 12 bytes.
> >
> > Perhaps, if you elaborate on how 'remainder' can become > 999?
> >
> 
> Yeah, I guess it can't. Not sure what we do about such false
> positives, do we have some common way to suppress them?

The only way I've found is to 'launder' the buffer size using
OPTIMISER_HIDE_VAR().
Although I can imagine an update to gcc that checks sizeof (buffer)
as well - so that would also need laundering.

You actually want:
#define OPTIMER_HIDE_VAL(x) \
  ({ __auto_type _x = x; OPTIMER_HIDE_VAR(_x); _x;})
so you can do:
	snprintf(OPTIMISER_HIDE_VAL(buffer), OPTOMISER_HIDE_VAL(sizeof buffer), fmt, ...)

Perhaps that could be snprint_truncate() ?

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
Re: [PATCH] lib: string_helpers: fix potential snprintf() output truncation
Posted by Andy Shevchenko 1 month ago
On Tue, Oct 22, 2024 at 10:30 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
> On Tue, Oct 22, 2024 at 9:15 AM Jiri Slaby <jirislaby@kernel.org> wrote:
> >
> > On 21. 10. 24, 12:04, Bartosz Golaszewski wrote:
> > > From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> > >
> > > The output of ".%03u" with the unsigned int in range [0, 4294966295] may
> > > get truncated if the target buffer is not 12 bytes.
> >
> > Perhaps, if you elaborate on how 'remainder' can become > 999?
>
> Yeah, I guess it can't. Not sure what we do about such false
> positives, do we have some common way to suppress them?

I already pointed out these kinds of warnings from GCC.
https://lore.kernel.org/all/Zt73a3t8Y8uH5MHG@smile.fi.intel.com/

-- 
With Best Regards,
Andy Shevchenko
Re: [PATCH] lib: string_helpers: fix potential snprintf() output truncation
Posted by Bartosz Golaszewski 1 month ago
On Mon, Oct 21, 2024 at 12:04 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> The output of ".%03u" with the unsigned int in range [0, 4294966295] may
> get truncated if the target buffer is not 12 bytes.
>
> Fixes: 3c9f3681d0b4 ("[SCSI] lib: add generic helper to print sizes rounded to the correct SI range")
> Cc: stable@vger.kernel.org
> Reviewed-by: Andy Shevchenko <andy@kernel.org>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> ---
>  lib/string_helpers.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/lib/string_helpers.c b/lib/string_helpers.c
> index 4f887aa62fa0..91fa37b5c510 100644
> --- a/lib/string_helpers.c
> +++ b/lib/string_helpers.c
> @@ -57,7 +57,7 @@ int string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
>         static const unsigned int rounding[] = { 500, 50, 5 };
>         int i = 0, j;
>         u32 remainder = 0, sf_cap;
> -       char tmp[8];
> +       char tmp[12];
>         const char *unit;
>
>         tmp[0] = '\0';
> --
> 2.43.0
>

Sorry for the noise but the tag should have said [RESEND PATCH].

Bart