Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scsi: ipr: Work around fortify-string warning

The ipr_log_vpd_compact() function triggers a fortified memcpy() warning
about a potential string overflow with all versions of clang:

In file included from drivers/scsi/ipr.c:43:
In file included from include/linux/string.h:254:
include/linux/fortify-string.h:520:4: error: call to '__write_overflow_field' declared with 'warning' attribute: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror,-Wattribute-warning]
__write_overflow_field(p_size_field, size);
^
include/linux/fortify-string.h:520:4: error: call to '__write_overflow_field' declared with 'warning' attribute: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror,-Wattribute-warning]
2 errors generated.

I don't see anything actually wrong with the function, but this is the only
instance I can reproduce of the fortification going wrong in the kernel at
the moment, so the easiest solution may be to rewrite the function into
something that does not trigger the warning.

Instead of having a combined buffer for vendor/device/serial strings, use
three separate local variables and just truncate the whitespace
individually.

Link: https://lore.kernel.org/r/20230214132831.2118392-1-arnd@kernel.org
Cc: Kees Cook <keescook@chromium.org>
Fixes: 8cf093e275d0 ("[SCSI] ipr: Improved dual adapter errors")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Acked-by: Brian King <brking@linux.vnet.ibm.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Arnd Bergmann and committed by
Martin K. Petersen
ee4e7dfe 3a2d1efa

+21 -20
+21 -20
drivers/scsi/ipr.c
··· 1516 1516 } 1517 1517 1518 1518 /** 1519 - * strip_and_pad_whitespace - Strip and pad trailing whitespace. 1520 - * @i: index into buffer 1521 - * @buf: string to modify 1519 + * strip_whitespace - Strip and pad trailing whitespace. 1520 + * @i: size of buffer 1521 + * @buf: string to modify 1522 1522 * 1523 - * This function will strip all trailing whitespace, pad the end 1524 - * of the string with a single space, and NULL terminate the string. 1523 + * This function will strip all trailing whitespace and 1524 + * NUL terminate the string. 1525 1525 * 1526 - * Return value: 1527 - * new length of string 1528 1526 **/ 1529 - static int strip_and_pad_whitespace(int i, char *buf) 1527 + static void strip_whitespace(int i, char *buf) 1530 1528 { 1529 + if (i < 1) 1530 + return; 1531 + i--; 1531 1532 while (i && buf[i] == ' ') 1532 1533 i--; 1533 - buf[i+1] = ' '; 1534 - buf[i+2] = '\0'; 1535 - return i + 2; 1534 + buf[i+1] = '\0'; 1536 1535 } 1537 1536 1538 1537 /** ··· 1546 1547 static void ipr_log_vpd_compact(char *prefix, struct ipr_hostrcb *hostrcb, 1547 1548 struct ipr_vpd *vpd) 1548 1549 { 1549 - char buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN + IPR_SERIAL_NUM_LEN + 3]; 1550 - int i = 0; 1550 + char vendor_id[IPR_VENDOR_ID_LEN + 1]; 1551 + char product_id[IPR_PROD_ID_LEN + 1]; 1552 + char sn[IPR_SERIAL_NUM_LEN + 1]; 1551 1553 1552 - memcpy(buffer, vpd->vpids.vendor_id, IPR_VENDOR_ID_LEN); 1553 - i = strip_and_pad_whitespace(IPR_VENDOR_ID_LEN - 1, buffer); 1554 + memcpy(vendor_id, vpd->vpids.vendor_id, IPR_VENDOR_ID_LEN); 1555 + strip_whitespace(IPR_VENDOR_ID_LEN, vendor_id); 1554 1556 1555 - memcpy(&buffer[i], vpd->vpids.product_id, IPR_PROD_ID_LEN); 1556 - i = strip_and_pad_whitespace(i + IPR_PROD_ID_LEN - 1, buffer); 1557 + memcpy(product_id, vpd->vpids.product_id, IPR_PROD_ID_LEN); 1558 + strip_whitespace(IPR_PROD_ID_LEN, product_id); 1557 1559 1558 - memcpy(&buffer[i], vpd->sn, IPR_SERIAL_NUM_LEN); 1559 - buffer[IPR_SERIAL_NUM_LEN + i] = '\0'; 1560 + memcpy(sn, vpd->sn, IPR_SERIAL_NUM_LEN); 1561 + strip_whitespace(IPR_SERIAL_NUM_LEN, sn); 1560 1562 1561 - ipr_hcam_err(hostrcb, "%s VPID/SN: %s\n", prefix, buffer); 1563 + ipr_hcam_err(hostrcb, "%s VPID/SN: %s %s %s\n", prefix, 1564 + vendor_id, product_id, sn); 1562 1565 } 1563 1566 1564 1567 /**