lib: string_helpers: fix potential snprintf() output truncation
Subsystems (3)
PATCH 1/1 lib: string_helpers: fix potential snprintf() output truncation
From: Bartosz Golaszewski <[email protected]>
The output of ".%03u" with the unsigned int in range [0, 4294966295] may get truncated if the target buffer is not 12 bytes.
--- lib/string_helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
lib/string_helpers.c +1 -1
@@ -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' ;
Signature · 1 line
2.43.0
Quoted 28 lines · Bartosz Golaszewski
From: Bartosz Golaszewski <[email protected]>
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")Reviewed-by Andy Shevchenko <[email protected]>Signed-off-by Bartosz Golaszewski <[email protected]>--- lib/string_helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)lib/string_helpers.c +1
-2@@ -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' ; --
Quoted 2 lines
2.43.0
Sorry for the noise but the tag should have said [RESEND PATCH].
Bart
Quoted 4 lines · Bartosz Golaszewski
From: Bartosz Golaszewski <[email protected]>
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?
Quoted 21 lines
Fixes 3c9f3681d0b4 ("[SCSI] lib: add generic helper to print sizes rounded to the correct SI range")Reviewed-by Andy Shevchenko <[email protected]>Signed-off-by Bartosz Golaszewski <[email protected]>--- lib/string_helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)lib/string_helpers.c +1
-1@@ -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' ;
Signature · 2 lines
js suse labs
Quoted 9 lines · Jiri Slaby
Quoted 4 lines · Bartosz Golaszewski
From: Bartosz Golaszewski <[email protected]>
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
Quoted 6 lines · Bartosz Golaszewski
Quoted 4 lines · Jiri Slaby
Quoted 2 lines · Bartosz Golaszewski
From: Bartosz Golaszewski <[email protected]>
Quoted 7 lines
Quoted 4 lines
Quoted 2 lines
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/[email protected]/
Signature · 2 lines
With Best Regards, Andy Shevchenko
From: Bartosz Golaszewski
Quoted 7 lines
Sent: 22 October 2024 08:30
Quoted 4 lines · Jiri Slaby
Quoted 2 lines · Bartosz Golaszewski
From: Bartosz Golaszewski <[email protected]>
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
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)
Quoted 8 lines · Jiri Slaby
Quoted 4 lines · Bartosz Golaszewski
From: Bartosz Golaszewski <[email protected]>
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.
Signature · 2 lines
With Best Regards, Andy Shevchenko
Quoted 8 lines · Andy Shevchenko
Quoted 7 lines · Jiri Slaby
Quoted 4 lines · Bartosz Golaszewski
From: Bartosz Golaszewski <[email protected]>
The output of ".%03u" with the unsigned int in range [0, 4294966295] may get truncated if the target buffer is not 12 bytes.
Quoted 8 lines
Quoted 1 line
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=1for 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:
lib/string_helpers.c +5 -11
@@ -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
On Tue, 2024-10-22 at 15:46 +0200, Rasmus Villemoes wrote:
[...]
Quoted 9 lines
- 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