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

scsi: libsas: Introduce struct smp_disc_resp

When compiling with gcc 12, several warnings are thrown by gcc when
compiling drivers/scsi/libsas/sas_expander.c, e.g.:

In function ‘sas_get_phy_change_count’,
inlined from ‘sas_find_bcast_phy.constprop’ at
drivers/scsi/libsas/sas_expander.c:1737:9:
drivers/scsi/libsas/sas_expander.c:1697:39: warning: array subscript
‘struct smp_resp[0]’ is partly outside array bounds of ‘unsigned
char[56]’ [-Warray-bounds]
1697 | *pcc = disc_resp->disc.change_count;
| ~~~~~~~~~~~~~~~^~~~~~~~~~~~~

This is due to the use of the struct smp_resp to aggregate all possible
response types using a union but allocating a response buffer with a size
exactly equal to the size of the response type needed. This leads to access
to fields of struct smp_resp from an allocated memory area that is smaller
than the size of struct smp_resp.

Fix this by defining struct smp_disc_resp for sas discovery operations.
Since this structure and the generic struct smp_resp are identical for
the little endian and big endian archs, move the definition of these
structures at the end of include/scsi/sas.h to avoid repeating their
definition.

Link: https://lore.kernel.org/r/20220609022456.409087-2-damien.lemoal@opensource.wdc.com
Reviewed-by: John Garry <john.garry@huawei.com>
Signed-off-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Damien Le Moal and committed by
Martin K. Petersen
c3752f44 0f4d7d55

+26 -34
+14 -18
drivers/scsi/libsas/sas_expander.c
··· 175 175 return dr->attached_dev_type; 176 176 } 177 177 178 - static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp) 178 + static void sas_set_ex_phy(struct domain_device *dev, int phy_id, 179 + struct smp_disc_resp *disc_resp) 179 180 { 180 181 enum sas_device_type dev_type; 181 182 enum sas_linkrate linkrate; 182 183 u8 sas_addr[SAS_ADDR_SIZE]; 183 - struct smp_resp *resp = rsp; 184 - struct discover_resp *dr = &resp->disc; 184 + struct discover_resp *dr = &disc_resp->disc; 185 185 struct sas_ha_struct *ha = dev->port->ha; 186 186 struct expander_device *ex = &dev->ex_dev; 187 187 struct ex_phy *phy = &ex->ex_phy[phy_id]; ··· 198 198 BUG_ON(!phy->phy); 199 199 } 200 200 201 - switch (resp->result) { 201 + switch (disc_resp->result) { 202 202 case SMP_RESP_PHY_VACANT: 203 203 phy->phy_state = PHY_VACANT; 204 204 break; ··· 347 347 } 348 348 349 349 #define DISCOVER_REQ_SIZE 16 350 - #define DISCOVER_RESP_SIZE 56 350 + #define DISCOVER_RESP_SIZE sizeof(struct smp_disc_resp) 351 351 352 352 static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req, 353 - u8 *disc_resp, int single) 353 + struct smp_disc_resp *disc_resp, 354 + int single) 354 355 { 355 - struct discover_resp *dr; 356 + struct discover_resp *dr = &disc_resp->disc; 356 357 int res; 357 358 358 359 disc_req[9] = single; ··· 362 361 disc_resp, DISCOVER_RESP_SIZE); 363 362 if (res) 364 363 return res; 365 - dr = &((struct smp_resp *)disc_resp)->disc; 366 364 if (memcmp(dev->sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE) == 0) { 367 365 pr_notice("Found loopback topology, just ignore it!\n"); 368 366 return 0; ··· 375 375 struct expander_device *ex = &dev->ex_dev; 376 376 int res = 0; 377 377 u8 *disc_req; 378 - u8 *disc_resp; 378 + struct smp_disc_resp *disc_resp; 379 379 380 380 disc_req = alloc_smp_req(DISCOVER_REQ_SIZE); 381 381 if (!disc_req) ··· 1657 1657 /* ---------- Domain revalidation ---------- */ 1658 1658 1659 1659 static int sas_get_phy_discover(struct domain_device *dev, 1660 - int phy_id, struct smp_resp *disc_resp) 1660 + int phy_id, struct smp_disc_resp *disc_resp) 1661 1661 { 1662 1662 int res; 1663 1663 u8 *disc_req; ··· 1673 1673 disc_resp, DISCOVER_RESP_SIZE); 1674 1674 if (res) 1675 1675 goto out; 1676 - else if (disc_resp->result != SMP_RESP_FUNC_ACC) { 1676 + if (disc_resp->result != SMP_RESP_FUNC_ACC) 1677 1677 res = disc_resp->result; 1678 - goto out; 1679 - } 1680 1678 out: 1681 1679 kfree(disc_req); 1682 1680 return res; ··· 1684 1686 int phy_id, int *pcc) 1685 1687 { 1686 1688 int res; 1687 - struct smp_resp *disc_resp; 1689 + struct smp_disc_resp *disc_resp; 1688 1690 1689 1691 disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE); 1690 1692 if (!disc_resp) ··· 1702 1704 u8 *sas_addr, enum sas_device_type *type) 1703 1705 { 1704 1706 int res; 1705 - struct smp_resp *disc_resp; 1706 - struct discover_resp *dr; 1707 + struct smp_disc_resp *disc_resp; 1707 1708 1708 1709 disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE); 1709 1710 if (!disc_resp) 1710 1711 return -ENOMEM; 1711 - dr = &disc_resp->disc; 1712 1712 1713 1713 res = sas_get_phy_discover(dev, phy_id, disc_resp); 1714 1714 if (res == 0) { 1715 1715 memcpy(sas_addr, disc_resp->disc.attached_sas_addr, 1716 1716 SAS_ADDR_SIZE); 1717 - *type = to_dev_type(dr); 1717 + *type = to_dev_type(&disc_resp->disc); 1718 1718 if (*type == 0) 1719 1719 memset(sas_addr, 0, SAS_ADDR_SIZE); 1720 1720 }
+12 -16
include/scsi/sas.h
··· 471 471 __be32 crc; 472 472 } __attribute__ ((packed)); 473 473 474 - struct smp_resp { 475 - u8 frame_type; 476 - u8 function; 477 - u8 result; 478 - u8 reserved; 479 - union { 480 - struct report_general_resp rg; 481 - struct discover_resp disc; 482 - struct report_phy_sata_resp rps; 483 - }; 484 - } __attribute__ ((packed)); 485 - 486 474 #elif defined(__BIG_ENDIAN_BITFIELD) 487 475 struct sas_identify_frame { 488 476 /* Byte 0 */ ··· 692 704 __be32 crc; 693 705 } __attribute__ ((packed)); 694 706 707 + #else 708 + #error "Bitfield order not defined!" 709 + #endif 710 + 711 + struct smp_disc_resp { 712 + u8 frame_type; 713 + u8 function; 714 + u8 result; 715 + u8 reserved; 716 + struct discover_resp disc; 717 + } __attribute__ ((packed)); 718 + 695 719 struct smp_resp { 696 720 u8 frame_type; 697 721 u8 function; ··· 715 715 struct report_phy_sata_resp rps; 716 716 }; 717 717 } __attribute__ ((packed)); 718 - 719 - #else 720 - #error "Bitfield order not defined!" 721 - #endif 722 718 723 719 #endif /* _SAS_H_ */