Re: [PATCH] scsi: ipr: work around fortify-string warning

From: Arnd Bergmann
Date: Tue Feb 14 2023 - 02:17:13 EST


On Tue, Feb 14, 2023, at 04:59, Damien Le Moal wrote:
> On 2/13/23 19:10, Arnd Bergmann wrote:
>> From: Arnd Bergmann <arnd@xxxxxxxx>

>> **/
>> -static int strip_and_pad_whitespace(int i, char *buf)
>> +static void strip_whitespace(int i, char *buf)
>> {
>> while (i && buf[i] == ' ')
>> i--;
>> - buf[i+1] = ' ';
>> - buf[i+2] = '\0';
>> - return i + 2;
>> + buf[i+1] = '\0';
>
> If i is now the size of the buffer, this is a buffer overflow, no ? And
> the initial loop should start at "i - 1" I think...

Right, I definitely have the wrong length here.

>> }
>>
>> /**
>> @@ -1547,19 +1543,21 @@ static int strip_and_pad_whitespace(int i, char *buf)
>> static void ipr_log_vpd_compact(char *prefix, struct ipr_hostrcb *hostrcb,
>> struct ipr_vpd *vpd)
>> {
>> - char buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN + IPR_SERIAL_NUM_LEN + 3];
>> - int i = 0;
>> + char vendor_id[IPR_VENDOR_ID_LEN + 1];
>
> ...but the size is in fact "i + 1"... So in strip_whitespace(), i is the
> index of the last possible character in the string, and given that the
> string may be much shorter, that function may not actually strip
> whitespaces after the string...

I think aside from the off-by-one bug I introduced, this is not
a (new) problem as the old code already assumed that the input
is padded with spaces rather than nul-terminated.

>> + char product_id[IPR_PROD_ID_LEN + 1];
>> + char sn[IPR_SERIAL_NUM_LEN + 1];
>>
>> - memcpy(buffer, vpd->vpids.vendor_id, IPR_VENDOR_ID_LEN);
>> - i = strip_and_pad_whitespace(IPR_VENDOR_ID_LEN - 1, buffer);
>> + memcpy(vendor_id, vpd->vpids.vendor_id, IPR_VENDOR_ID_LEN);
>> + strip_whitespace(IPR_VENDOR_ID_LEN, vendor_id);
>
> So this call should really be:
>
> strip_whitespace(strlen(vendor_id) - 1, vendor_id);
>
> Which means that this helper can be turned into:
>
> static void strip_whitespace(char *buf)
> {
> int i = strlen(buf) - 1;
>
> while (i > 0 && buf[i] == ' ')
> i--;
> buf[i+1] = '\0';
> }
>
> Unless I am missing something :)

The strlen() here requires the input to be a properly terminated string,
so this would at least require adding a \0.

Also, if the input is a short nul-terminated string instead of
a space padded array, we probably don't need to strip the trailing
whitespace, or at least the original version didn't either.

Let me try to respin my patch with just the off-by-one error
fixed but otherwise keeping the output of ipr_log_vpd_compact()
unchanged.

Arnd