Linux SCSI subsystem development
 help / color / mirror / Atom feed
* [PATCH] scsi: ses: bound the page 2 descriptor walk to the page 2 buffer
@ 2026-07-06  5:46 Bryam Vargas via B4 Relay
  2026-07-06  6:03 ` sashiko-bot
  0 siblings, 1 reply; 2+ messages in thread
From: Bryam Vargas via B4 Relay @ 2026-07-06  5:46 UTC (permalink / raw)
  To: Martin K. Petersen, James E.J. Bottomley; +Cc: linux-scsi, linux-kernel

From: Bryam Vargas <hexlabsecurity@proton.me>

ses_get_page2_descriptor() and ses_set_page2_descriptor() walk the
enclosure status descriptors by advancing desc_ptr four bytes per page 1
element without bounding it against the page 2 allocation.  The
descriptor count comes from page 1 while page 2 is a separately sized
diagnostic page, both supplied by the enclosure device; a device that
reports more descriptors than page 2 can hold walks desc_ptr past the
buffer.  The get path then dereferences it, a four-byte out-of-bounds
heap read reachable through the component sysfs attributes, and the set
path writes four bytes past the buffer.

Stop each walk once the next descriptor would extend past the end of
page 2: the get path returns NULL, which its callers already handle, and
the set path stops before the copy.  Well-formed enclosures are
unaffected.  The unbounded walk was flagged by the Sashiko AI review
(https://sashiko.dev) of the page 2 header length fix.

Fixes: 9927c68864e9 ("[SCSI] ses: add new Enclosure ULD")
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
---
Reproduced with an in-kernel KASAN module that models the page 2 walk: a
page 1 declaring one component with an 8-byte page 2 makes the first
descriptor land at page2+12, four bytes past the kmalloc-8 object.  KASAN
reports slab-out-of-bounds Write (ses_set_page2_descriptor) and Read
(ses_get_page2_descriptor); the read returns adjacent heap rather than the
zeroed in-bounds bytes.  With the patch both walks stop before that access,
and a page 2 large enough for the page 1 descriptors is unchanged.

The pages are only device-supplied, so this needs a malicious or
malfunctioning SES enclosure; the write path additionally needs a
privileged write to the component sysfs attributes.

There is a separate, already-posted fix on this file for the page 2
status-page-header underflow ("scsi: ses: skip an enclosure status page
shorter than its header").  This one is independent -- the hunks do not
overlap and it applies on v7.2-rc1 either way.
---
 drivers/scsi/ses.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index 4c348645b04e..7e9c33809131 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -184,12 +184,21 @@ static int ses_set_page2_descriptor(struct enclosure_device *edev,
 	struct ses_device *ses_dev = edev->scratch;
 	unsigned char *type_ptr = ses_dev->page1_types;
 	unsigned char *desc_ptr = ses_dev->page2 + 8;
+	unsigned char *page2_end = ses_dev->page2 + ses_dev->page2_len;
 
 	/* Clear everything */
 	memset(desc_ptr, 0, ses_dev->page2_len - 8);
 	for (i = 0; i < ses_dev->page1_num_types; i++, type_ptr += 4) {
 		for (j = 0; j < type_ptr[1]; j++) {
 			desc_ptr += 4;
+			/*
+			 * The descriptor count comes from page 1 while page 2
+			 * is a separately sized diagnostic page; a device that
+			 * reports more descriptors than page 2 can hold would
+			 * walk desc_ptr past the buffer, so stop here.
+			 */
+			if (desc_ptr + 4 > page2_end)
+				goto out;
 			if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE &&
 			    type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE)
 				continue;
@@ -203,6 +212,7 @@ static int ses_set_page2_descriptor(struct enclosure_device *edev,
 		}
 	}
 
+out:
 	return ses_send_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len);
 }
 
@@ -214,6 +224,7 @@ static unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev,
 	struct ses_device *ses_dev = edev->scratch;
 	unsigned char *type_ptr = ses_dev->page1_types;
 	unsigned char *desc_ptr = ses_dev->page2 + 8;
+	unsigned char *page2_end = ses_dev->page2 + ses_dev->page2_len;
 
 	if (ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len))
 		return NULL;
@@ -221,6 +232,8 @@ static unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev,
 	for (i = 0; i < ses_dev->page1_num_types; i++, type_ptr += 4) {
 		for (j = 0; j < type_ptr[1]; j++) {
 			desc_ptr += 4;
+			if (desc_ptr + 4 > page2_end)
+				return NULL;
 			if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE &&
 			    type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE)
 				continue;

---
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
change-id: 20260706-b4-disp-29a05ca3-c1fe7cd9693a

Best regards,
-- 
Bryam Vargas <hexlabsecurity@proton.me>



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

end of thread, other threads:[~2026-07-06  6:03 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-06  5:46 [PATCH] scsi: ses: bound the page 2 descriptor walk to the page 2 buffer Bryam Vargas via B4 Relay
2026-07-06  6:03 ` sashiko-bot

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