[PATCH v2] scsi: core: validate VPD 0x83 descriptor bounds

Jiancheng Huang posted 1 patch 5 hours ago
drivers/scsi/scsi_lib.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
[PATCH v2] scsi: core: validate VPD 0x83 descriptor bounds
Posted by Jiancheng Huang 5 hours ago
scsi_vpd_lun_id() advances through VPD page 0x83 using each descriptor's
length before proving that the descriptor header and body fit in the
retained page. The priority helper and formatters can then read beyond a
truncated descriptor.

Reject pages shorter than the four-byte page header. Track the page end and
stop before calling designator_prio() unless both the descriptor header and
declared body are present.

Fixes: 9983bed3907c ("scsi: Add scsi_vpd_lun_id()")
Signed-off-by: Jiancheng Huang <jchuang@seu.edu.cn>
Assisted-by: Codex:gpt-5.6-luna
---
Changes in v2:
- Add the relevant public mailing lists to Cc; no source changes.

Evidence (v7.2-rc4 KUnit/KASAN oracle under bounded QEMU):
Source: confirmed/scsi_vpd_truncated_designator_sysfs_oob_raw_excerpt.log

[    2.628665] KTAP version 1
[    2.628739] 1..1
[    2.631405]     KTAP version 1
[    2.631565]     # Subtest: scsi-vpd-truncated-designator-sysfs
[    2.631858]     # module: scsi_mod
[    2.632142]     1..1
[    2.634467] scsi_vpd_truncated_designator_sysfs_test: invoking sdev_show_wwid oracle
[    2.635065] ==================================================================
[    2.635366] BUG: KASAN: slab-out-of-bounds in string_escape_mem+0x84d/0xb60
[    2.635782] Read of size 1 at addr ffff8880019b87e0 by task kunit_try_catch/64
[    2.635919] 
[    2.635985] CPU: 0 UID: 0 PID: 64 Comm: kunit_try_catch Tainted: G                 N  7.2.0-rc4-dirty #3 PREEMPT(full) 
[    2.635985] Tainted: [N]=TEST
[    2.635985] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[    2.635985] Call Trace:
[    2.635985]  <TASK>
[    2.635985]  dump_stack_lvl+0x53/0x70
[    2.635985]  print_report+0xd0/0x630
[    2.635985]  ? __pfx__raw_spin_lock_irqsave+0x10/0x10
[    2.635985]  ? string_escape_mem+0x84d/0xb60
[    2.635985]  kasan_report+0xe5/0x120
[    2.635985]  ? string_escape_mem+0x84d/0xb60
[    2.635985]  string_escape_mem+0x84d/0xb60

 drivers/scsi/scsi_lib.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index daeb3693f..5e0b84e2d 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -3365,7 +3365,7 @@ int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len)
 {
 	u8 cur_id_prio = 0;
 	u8 cur_id_size = 0;
-	const unsigned char *d, *cur_id_str;
+	const unsigned char *d, *cur_id_str, *end;
 	const struct scsi_vpd *vpd_pg83;
 	int id_size = -EINVAL;
 
@@ -3382,11 +3382,21 @@ int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len)
 		return -EINVAL;
 	}
 
+	if (vpd_pg83->len < 4) {
+		rcu_read_unlock();
+		return -EINVAL;
+	}
+
 	memset(id, 0, id_len);
-	for (d = vpd_pg83->data + 4;
-	     d < vpd_pg83->data + vpd_pg83->len;
+	end = vpd_pg83->data + vpd_pg83->len;
+	for (d = vpd_pg83->data + 4; end - d >= 4;
 	     d += d[3] + 4) {
-		u8 prio = designator_prio(d);
+		u8 prio;
+
+		if (d[3] > end - d - 4)
+			break;
+
+		prio = designator_prio(d);
 
 		if (prio == 0 || cur_id_prio > prio)
 			continue;
-- 
2.43.0