mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2 0/2] scsi: pm8001: Fix struct layout and FORTIFY_SOURCE crash
@ 2026-05-26 14:29 Ronja Meyer
  2026-05-26 14:29 ` [PATCH v2 1/2] scsi: libsas: Define sas_identify_frame_local via struct_group Ronja Meyer
  2026-05-26 14:29 ` [PATCH v2 2/2] scsi: pm8001: Match hw_event_resp to HBA data layout Ronja Meyer
  0 siblings, 2 replies; 3+ messages in thread
From: Ronja Meyer @ 2026-05-26 14:29 UTC (permalink / raw)
  To: Jack Wang, James E.J. Bottomley, Martin K. Petersen, Tom Peng,
	Kevin Ao, Lindar Liu, James Bottomley
  Cc: jack wang, linux-scsi, linux-kernel, Ronja Meyer, stable, Igor Pylypiv

This patch series:
- Fixes a crash when the driver is built with FORTIFY_SOURCE=y.
- Aligns the struct layout of hw_event_resp to what the HBA believes
  it looks like.
- Simplifies code previously required to work around the incorrect
  struct definition.

Testing:
- Verified I can still read from disks using the pm80xx driver.
- I do not have pm8001 hardware available to verify against.

Changes in v2:
- Define sas_identify_frame_local via struct_group.
- Move pm8001 phy_start_req _local change to patch 2.
- Don't mess with whitespace unnecessarily.
- Link to v1: https://lore.kernel.org/r/20260515-fortify_pm80-v1-0-2863187f6d4b@google.com

Signed-off-by: Ronja Meyer <rnj@google.com>
---
Ronja Meyer (2):
      scsi: libsas: Define sas_identify_frame_local via struct_group
      scsi: pm8001: Match hw_event_resp to HBA data layout

 drivers/scsi/pm8001/pm8001_hwi.c |   6 +-
 drivers/scsi/pm8001/pm8001_hwi.h |   6 +-
 drivers/scsi/pm8001/pm80xx_hwi.c |   6 +-
 drivers/scsi/pm8001/pm80xx_hwi.h | 100 +--------------------------
 include/scsi/sas.h               | 144 ++++++++++++++++++++-------------------
 5 files changed, 85 insertions(+), 177 deletions(-)
---
base-commit: b71cb088b2e3427924a470fc43e7aedb8a40d2e3
change-id: 20260515-fortify_pm80-b527a10c89d0

Best regards,
-- 
Ronja Meyer <rnj@google.com>


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH v2 1/2] scsi: libsas: Define sas_identify_frame_local via struct_group
  2026-05-26 14:29 [PATCH v2 0/2] scsi: pm8001: Fix struct layout and FORTIFY_SOURCE crash Ronja Meyer
@ 2026-05-26 14:29 ` Ronja Meyer
  2026-05-26 14:29 ` [PATCH v2 2/2] scsi: pm8001: Match hw_event_resp to HBA data layout Ronja Meyer
  1 sibling, 0 replies; 3+ messages in thread
From: Ronja Meyer @ 2026-05-26 14:29 UTC (permalink / raw)
  To: Jack Wang, James E.J. Bottomley, Martin K. Petersen, Tom Peng,
	Kevin Ao, Lindar Liu, James Bottomley
  Cc: jack wang, linux-scsi, linux-kernel, Ronja Meyer, stable

The pm80 drivers both need a variant of the sas_identify_frame struct
without the CRC struct member. The pm80xx driver previously duplicated
the struct, omitting this field, to sas_identify_frame_local in:
commit 5990fd57ebea ("scsi: pm80xx: redefine sas_identify_frame structure")

The pm8001 driver also needs the _local variant. Instead of duplicating
the struct again, let's define it as a struct group inside the main
sas_identify_frame struct and remove the duplicate in the pm80xx driver.

Sending to stable, as this change is required for the fortify-panic fix
later in this chain to apply cleanly.

Cc: stable@vger.kernel.org
Fixes: dbf9bfe61571 ("[SCSI] pm8001: add SAS/SATA HBA driver")
Signed-off-by: Ronja Meyer <rnj@google.com>
---
 drivers/scsi/pm8001/pm80xx_hwi.h |  96 --------------------------
 include/scsi/sas.h               | 144 ++++++++++++++++++++-------------------
 2 files changed, 74 insertions(+), 166 deletions(-)

diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h
index d8a63b7fed6a..2fa54b901a2e 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.h
+++ b/drivers/scsi/pm8001/pm80xx_hwi.h
@@ -236,102 +236,6 @@
 /* Port recovery timeout, 10000 ms for PM8006 controller */
 #define CHIP_8006_PORT_RECOVERY_TIMEOUT 0x640000
 
-#ifdef __LITTLE_ENDIAN_BITFIELD
-struct sas_identify_frame_local {
-	/* Byte 0 */
-	u8  frame_type:4;
-	u8  dev_type:3;
-	u8  _un0:1;
-
-	/* Byte 1 */
-	u8  _un1;
-
-	/* Byte 2 */
-	union {
-		struct {
-			u8  _un20:1;
-			u8  smp_iport:1;
-			u8  stp_iport:1;
-			u8  ssp_iport:1;
-			u8  _un247:4;
-		};
-		u8 initiator_bits;
-	};
-
-	/* Byte 3 */
-	union {
-		struct {
-			u8  _un30:1;
-			u8 smp_tport:1;
-			u8 stp_tport:1;
-			u8 ssp_tport:1;
-			u8 _un347:4;
-		};
-		u8 target_bits;
-	};
-
-	/* Byte 4 - 11 */
-	u8 _un4_11[8];
-
-	/* Byte 12 - 19 */
-	u8 sas_addr[SAS_ADDR_SIZE];
-
-	/* Byte 20 */
-	u8 phy_id;
-
-	u8 _un21_27[7];
-
-} __packed;
-
-#elif defined(__BIG_ENDIAN_BITFIELD)
-struct sas_identify_frame_local {
-	/* Byte 0 */
-	u8  _un0:1;
-	u8  dev_type:3;
-	u8  frame_type:4;
-
-	/* Byte 1 */
-	u8  _un1;
-
-	/* Byte 2 */
-	union {
-		struct {
-			u8  _un247:4;
-			u8  ssp_iport:1;
-			u8  stp_iport:1;
-			u8  smp_iport:1;
-			u8  _un20:1;
-		};
-		u8 initiator_bits;
-	};
-
-	/* Byte 3 */
-	union {
-		struct {
-			u8 _un347:4;
-			u8 ssp_tport:1;
-			u8 stp_tport:1;
-			u8 smp_tport:1;
-			u8 _un30:1;
-		};
-		u8 target_bits;
-	};
-
-	/* Byte 4 - 11 */
-	u8 _un4_11[8];
-
-	/* Byte 12 - 19 */
-	u8 sas_addr[SAS_ADDR_SIZE];
-
-	/* Byte 20 */
-	u8 phy_id;
-
-	u8 _un21_27[7];
-} __packed;
-#else
-#error "Bitfield order not defined!"
-#endif
-
 struct mpi_msg_hdr {
 	__le32	header;	/* Bits [11:0] - Message operation code */
 	/* Bits [15:12] - Message Category */
diff --git a/include/scsi/sas.h b/include/scsi/sas.h
index 71b749bed3b0..90f3081a3270 100644
--- a/include/scsi/sas.h
+++ b/include/scsi/sas.h
@@ -252,48 +252,50 @@ struct host_to_dev_fis {
  */
 #ifdef __LITTLE_ENDIAN_BITFIELD
 struct sas_identify_frame {
-	/* Byte 0 */
-	u8  frame_type:4;
-	u8  dev_type:3;
-	u8  _un0:1;
-
-	/* Byte 1 */
-	u8  _un1;
-
-	/* Byte 2 */
-	union {
-		struct {
-			u8  _un20:1;
-			u8  smp_iport:1;
-			u8  stp_iport:1;
-			u8  ssp_iport:1;
-			u8  _un247:4;
+	__struct_group(sas_identify_frame_local, payload, __packed,
+		/* Byte 0 */
+		u8  frame_type:4;
+		u8  dev_type:3;
+		u8  _un0:1;
+
+		/* Byte 1 */
+		u8  _un1;
+
+		/* Byte 2 */
+		union {
+			struct {
+				u8  _un20:1;
+				u8  smp_iport:1;
+				u8  stp_iport:1;
+				u8  ssp_iport:1;
+				u8  _un247:4;
+			};
+			u8 initiator_bits;
 		};
-		u8 initiator_bits;
-	};
 
-	/* Byte 3 */
-	union {
-		struct {
-			u8  _un30:1;
-			u8 smp_tport:1;
-			u8 stp_tport:1;
-			u8 ssp_tport:1;
-			u8 _un347:4;
+		/* Byte 3 */
+		union {
+			struct {
+				u8  _un30:1;
+				u8 smp_tport:1;
+				u8 stp_tport:1;
+				u8 ssp_tport:1;
+				u8 _un347:4;
+			};
+			u8 target_bits;
 		};
-		u8 target_bits;
-	};
 
-	/* Byte 4 - 11 */
-	u8 _un4_11[8];
+		/* Byte 4 - 11 */
+		u8 _un4_11[8];
 
-	/* Byte 12 - 19 */
-	u8 sas_addr[SAS_ADDR_SIZE];
+		/* Byte 12 - 19 */
+		u8 sas_addr[SAS_ADDR_SIZE];
 
-	/* Byte 20 */
-	u8 phy_id;
+		/* Byte 20 */
+		u8 phy_id;
 
-	u8 _un21_27[7];
+		u8 _un21_27[7];
+	);
 
 	__be32 crc;
 } __attribute__ ((packed));
@@ -473,48 +475,50 @@ struct report_phy_sata_resp {
 
 #elif defined(__BIG_ENDIAN_BITFIELD)
 struct sas_identify_frame {
-	/* Byte 0 */
-	u8  _un0:1;
-	u8  dev_type:3;
-	u8  frame_type:4;
-
-	/* Byte 1 */
-	u8  _un1;
-
-	/* Byte 2 */
-	union {
-		struct {
-			u8  _un247:4;
-			u8  ssp_iport:1;
-			u8  stp_iport:1;
-			u8  smp_iport:1;
-			u8  _un20:1;
+	__struct_group(sas_identify_frame_local, payload, __packed,
+		/* Byte 0 */
+		u8  _un0:1;
+		u8  dev_type:3;
+		u8  frame_type:4;
+
+		/* Byte 1 */
+		u8  _un1;
+
+		/* Byte 2 */
+		union {
+			struct {
+				u8  _un247:4;
+				u8  ssp_iport:1;
+				u8  stp_iport:1;
+				u8  smp_iport:1;
+				u8  _un20:1;
+			};
+			u8 initiator_bits;
 		};
-		u8 initiator_bits;
-	};
 
-	/* Byte 3 */
-	union {
-		struct {
-			u8 _un347:4;
-			u8 ssp_tport:1;
-			u8 stp_tport:1;
-			u8 smp_tport:1;
-			u8 _un30:1;
+		/* Byte 3 */
+		union {
+			struct {
+				u8 _un347:4;
+				u8 ssp_tport:1;
+				u8 stp_tport:1;
+				u8 smp_tport:1;
+				u8 _un30:1;
+			};
+			u8 target_bits;
 		};
-		u8 target_bits;
-	};
 
-	/* Byte 4 - 11 */
-	u8 _un4_11[8];
+		/* Byte 4 - 11 */
+		u8 _un4_11[8];
 
-	/* Byte 12 - 19 */
-	u8 sas_addr[SAS_ADDR_SIZE];
+		/* Byte 12 - 19 */
+		u8 sas_addr[SAS_ADDR_SIZE];
 
-	/* Byte 20 */
-	u8 phy_id;
+		/* Byte 20 */
+		u8 phy_id;
 
-	u8 _un21_27[7];
+		u8 _un21_27[7];
+	);
 
 	__be32 crc;
 } __attribute__ ((packed));

-- 
2.54.0.746.g67dd491aae-goog


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH v2 2/2] scsi: pm8001: Match hw_event_resp to HBA data layout
  2026-05-26 14:29 [PATCH v2 0/2] scsi: pm8001: Fix struct layout and FORTIFY_SOURCE crash Ronja Meyer
  2026-05-26 14:29 ` [PATCH v2 1/2] scsi: libsas: Define sas_identify_frame_local via struct_group Ronja Meyer
@ 2026-05-26 14:29 ` Ronja Meyer
  1 sibling, 0 replies; 3+ messages in thread
From: Ronja Meyer @ 2026-05-26 14:29 UTC (permalink / raw)
  To: Jack Wang, James E.J. Bottomley, Martin K. Petersen, Tom Peng,
	Kevin Ao, Lindar Liu, James Bottomley
  Cc: jack wang, linux-scsi, linux-kernel, Ronja Meyer, stable, Igor Pylypiv

Correct the hw_event_resp and phy_start_req struct definitions to match
the layout of data sent by the HBA. Remove pointer arithmetics working
around the previously incorrect struct definitions.

Looking at the struct definition before this patch:
  struct hw_event_resp {
           [...]
           struct	sas_identify_frame sas_identify;
           struct dev_to_host_fis	sata_fis;
   } __attribute__((packed, aligned(4)));

Previously the memcpy() in hw_event_sata_phy_up() crossed reading
from the sas_identify struct over into the sata_fis struct. This was
necessary, because the hw_event_resp struct definition didn't align
properly with what the HBA actually sent. The member sas_identify right
before the member sata_fis was 4 bytes too long, causing the first
4 bytes of the sata_fis to be shifted into the last 4 bytes of
sas_identify. The code worked around this by subtracting 4 bytes from
both the sata_fis pointer, as well as sizeof(sas_identify), when they
were used.

FORTIFY_SOURCE detected this deliberate choice to cross struct member
boundaries as an out-of-bounds read, even though in this case it didn't
lead to a vulnerability. Hence the following fortify-panic was
triggered:

  kernel BUG at lib/string_helpers.c:1044!
  RIP: 0010:__fortify_panic+0x9/0x10
  hw_event_sata_phy_up+0xea/0x120 [pm80xx]
  process_one_iomb+0x634e/0x6360 [pm80xx]
  process_oq+0x391/0x430 [pm80xx]
  pm80xx_chip_isr+0x78/0x100 [pm80xx]
  tasklet_action_common+0x16a/0x2b0
  handle_softirqs+0xcd/0x2a0
  __irq_exit_rcu+0x50/0x100
  common_interrupt+0x89/0xa0

Furthermore hw_event_resp was 64 bytes before this patch, which is
4 bytes too long. Messages exchanged between the pm8001 and the host
kernel can be a maximum of 64 bytes, as defined in iomb_size. The
message structs defined in pm8001_hwi.h must have a size of 60 bytes,
in order to leave space for a 4 byte header that implicitly precedes
each message.

Luckily the code interacting with hw_event_resp doesn't ever seem to
read or write the last 4 bytes of the struct and doesn't seem to use
the incorrect size of the struct in a copy operation. Hence it doesn't
overflow in practice. Further the pm80xx driver was unaffected by this
bug. While the pm80xx struct was also 64 bytes, the message size on
pm80xx is 128 bytes. Hence it is able to fit the 68 byte header and
message without overflowing.

This is not security critical AFAICT.

Cc: stable@vger.kernel.org
Fixes: dbf9bfe61571 ("[SCSI] pm8001: add SAS/SATA HBA driver")
Co-developed-by: Igor Pylypiv <ipylypiv@google.com>
Signed-off-by: Igor Pylypiv <ipylypiv@google.com>
Signed-off-by: Ronja Meyer <rnj@google.com>
---
 drivers/scsi/pm8001/pm8001_hwi.c | 6 +++---
 drivers/scsi/pm8001/pm8001_hwi.h | 6 +++---
 drivers/scsi/pm8001/pm80xx_hwi.c | 6 +++---
 drivers/scsi/pm8001/pm80xx_hwi.h | 4 ++--
 4 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index fff8d877abb9..e90f2d98d8ed 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -3164,8 +3164,8 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
 	sas_notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE, GFP_ATOMIC);
 	spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags);
 	memcpy(phy->frame_rcvd, &pPayload->sas_identify,
-		sizeof(struct sas_identify_frame)-4);
-	phy->frame_rcvd_size = sizeof(struct sas_identify_frame) - 4;
+		sizeof(struct sas_identify_frame_local));
+	phy->frame_rcvd_size = sizeof(struct sas_identify_frame_local);
 	pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr);
 	spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
 	if (pm8001_ha->flags == PM8001F_RUN_TIME)
@@ -3208,7 +3208,7 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
 	phy->sas_phy.oob_mode = SATA_OOB_MODE;
 	sas_notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE, GFP_ATOMIC);
 	spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags);
-	memcpy(phy->frame_rcvd, ((u8 *)&pPayload->sata_fis - 4),
+	memcpy(phy->frame_rcvd, &pPayload->sata_fis,
 		sizeof(struct dev_to_host_fis));
 	phy->frame_rcvd_size = sizeof(struct dev_to_host_fis);
 	phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
diff --git a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h
index f1ce8df082b0..395be4fdbf81 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.h
+++ b/drivers/scsi/pm8001/pm8001_hwi.h
@@ -153,8 +153,8 @@ struct mpi_msg_hdr{
 struct phy_start_req {
 	__le32	tag;
 	__le32	ase_sh_lm_slr_phyid;
-	struct sas_identify_frame sas_identify;
-	u32	reserved[5];
+	struct sas_identify_frame_local sas_identify;	/* _local to omit CRC field */
+	u32	reserved[6];
 } __attribute__((packed, aligned(4)));
 
 
@@ -229,7 +229,7 @@ struct hw_event_resp {
 	__le32	lr_evt_status_phyid_portid;
 	__le32	evt_param;
 	__le32	npip_portstate;
-	struct sas_identify_frame	sas_identify;
+	struct sas_identify_frame_local	sas_identify;	/* _local to omit CRC field */
 	struct dev_to_host_fis	sata_fis;
 } __attribute__((packed, aligned(4)));
 
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index 954f307352e6..03293e9b84e6 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -3241,8 +3241,8 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
 	sas_notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE, GFP_ATOMIC);
 	spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags);
 	memcpy(phy->frame_rcvd, &pPayload->sas_identify,
-		sizeof(struct sas_identify_frame)-4);
-	phy->frame_rcvd_size = sizeof(struct sas_identify_frame) - 4;
+		sizeof(struct sas_identify_frame_local));
+	phy->frame_rcvd_size = sizeof(struct sas_identify_frame_local);
 	pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr);
 	spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
 	if (pm8001_ha->flags == PM8001F_RUN_TIME)
@@ -3289,7 +3289,7 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
 	phy->sas_phy.oob_mode = SATA_OOB_MODE;
 	sas_notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE, GFP_ATOMIC);
 	spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags);
-	memcpy(phy->frame_rcvd, ((u8 *)&pPayload->sata_fis - 4),
+	memcpy(phy->frame_rcvd, &pPayload->sata_fis,
 		sizeof(struct dev_to_host_fis));
 	phy->frame_rcvd_size = sizeof(struct dev_to_host_fis);
 	phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h
index 2fa54b901a2e..41f10c970125 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.h
+++ b/drivers/scsi/pm8001/pm80xx_hwi.h
@@ -255,7 +255,7 @@ struct mpi_msg_hdr {
 struct phy_start_req {
 	__le32	tag;
 	__le32	ase_sh_lm_slr_phyid;
-	struct sas_identify_frame_local sas_identify; /* 28 Bytes */
+	struct sas_identify_frame_local sas_identify;	/* _local to omit CRC field */
 	__le32 spasti;
 	u32	reserved[21];
 } __attribute__((packed, aligned(4)));
@@ -331,7 +331,7 @@ struct hw_event_resp {
 	__le32	lr_status_evt_portid;
 	__le32	evt_param;
 	__le32	phyid_npip_portstate;
-	struct sas_identify_frame	sas_identify;
+	struct sas_identify_frame_local	sas_identify;	/* _local to omit CRC field */
 	struct dev_to_host_fis	sata_fis;
 } __attribute__((packed, aligned(4)));
 

-- 
2.54.0.746.g67dd491aae-goog


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-05-26 14:29 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-26 14:29 [PATCH v2 0/2] scsi: pm8001: Fix struct layout and FORTIFY_SOURCE crash Ronja Meyer
2026-05-26 14:29 ` [PATCH v2 1/2] scsi: libsas: Define sas_identify_frame_local via struct_group Ronja Meyer
2026-05-26 14:29 ` [PATCH v2 2/2] scsi: pm8001: Match hw_event_resp to HBA data layout Ronja Meyer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®