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

From: Damien Le Moal
Date: Tue Feb 14 2023 - 02:28:05 EST


On 2/14/23 16:14, Arnd Bergmann wrote:
> 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.

Yeah. The HW probably always give the same amount of chars with short
strings completed by spaces...

>
>>> + 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

--
Damien Le Moal
Western Digital Research