[PATCH] scsi: pmcraid: bound the HCAM data length reported to user space
From: Yehyeong Lee
Date: Sun Oct 18 2026 - 21:39:52 EST
pmcraid_notify_ccn() and pmcraid_notify_ldn() take data_len out of the
HCAM header the IOA wrote into the coherent DMA buffer and pass it on to
pmcraid_notify_aen(), which uses it as the netlink attribute length:
data_size = le32_to_cpu(pinstance->ccn.hcam->data_len) +
sizeof(struct pmcraid_hcam_hdr);
...
nla_put(skb, PMCRAID_AEN_ATTR_EVENT, data_size, aen_msg);
data_len is never checked against the buffer it came from. The CCN
buffer is 4048 bytes, so an IOA reporting more than 4008 makes nla_put()
read past the end of it, and what it reads is multicast to whoever is
bound to the event group. The LDN buffer is 4112 bytes and has the same
problem above 4072.
Driving pmcraid_notify_ccn() with data_len one byte past the limit, with
the HCAM buffer allocated by kmalloc() at the production size because
dma_alloc_coherent() memory is page granular and not tracked by KASAN:
BUG: KASAN: slab-out-of-bounds in nla_put+0xc7/0x160
Read of size 4049 at addr 00000000622c2000 by task kunit_try_catch/19
CPU: 0 UID: 0 PID: 19 Comm: kunit_try_catch Tainted: G W N 7.3.0-rc7-g58161ead29e5-dirty #5 VOLUNTARY
Tainted: [W]=WARN, [N]=TEST
Call Trace:
[<6008af12>] ? dump_stack_lvl+0x5e/0x7a
[<6003e621>] ? _printk+0x0/0xd7
[<6004b21d>] ? print_report+0x14b/0x517
[<6003e621>] ? _printk+0x0/0xd7
[<606ffcb7>] ? nla_put+0xc7/0x160
[<603aeebb>] ? kasan_report+0x11b/0x160
[<60950e4d>] ? __alloc_skb+0x1bd/0x9c0
[<606ffcb7>] ? nla_put+0xc7/0x160
[<603afe70>] ? kasan_check_range+0x0/0x1c0
[<603affbe>] ? kasan_check_range+0x14e/0x1c0
[<603b0a41>] ? __asan_memcpy+0x31/0x80
[<606ffcb7>] ? nla_put+0xc7/0x160
[<608801af>] ? pmcraid_notify_aen+0x19f/0x440
[<60882ba7>] ? pmcraid_aen_ccn_oob_one+0x1a7/0x380
[<60213550>] ? ktime_get_ts64+0x0/0x2c0
[<606ea77c>] ? kunit_try_run_case+0x1bc/0x310
[<606ea5c0>] ? kunit_try_run_case+0x0/0x310
[<603b08f0>] ? __kasan_check_read+0x0/0x20
[<600af020>] ? um_set_signals+0x0/0x60
[<600af020>] ? um_set_signals+0x0/0x60
[<6012e3cd>] ? __kthread_parkme+0xdd/0x1c0
[<606ea5c0>] ? kunit_try_run_case+0x0/0x310
[<606f0840>] ? kunit_generic_run_threadfn_adapter+0x0/0x100
[<606f08bc>] ? kunit_generic_run_threadfn_adapter+0x7c/0x100
[<6013464e>] ? kthread+0x36e/0x560
[<601342e0>] ? kthread+0x0/0x560
[<6008f0de>] ? new_thread_handler+0xce/0x130
The buggy address belongs to the object at 00000000622c2000
which belongs to the cache kmalloc-4k of size 4096
The buggy address is located 0 bytes inside of
allocated 4048-byte region [00000000622c2000, 00000000622c2fd0)
W is a UML virtio warning and N marks the KUnit harness that drove the
call; neither comes from this path.
Clamp data_len to what the buffer can hold before it is used as a length.
A working IOA never reports more than that, so this does not change what
user space sees from one.
Found by inspection. Not tested on a MaxRAID adapter.
Fixes: 89a3681041507 ("[SCSI] pmcraid: PMC-Sierra MaxRAID driver to support 6Gb/s SAS RAID controller")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Yehyeong Lee <yhlee@xxxxxxxxxxxxxxxxxx>
---
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index 942a993932049..f59d5a775aebb 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -1451,6 +1451,17 @@ static int pmcraid_notify_aen(
return result;
}
+/* The IOA picks data_len, so cap it at what the HCAM buffer holds before it
+ * becomes a copy length. Returns the size to report, header included.
+ */
+static u32 pmcraid_hcam_data_size(__le32 data_len, size_t hcam_size)
+{
+ size_t hdr_size = sizeof(struct pmcraid_hcam_hdr);
+
+ return min_t(u32, le32_to_cpu(data_len), hcam_size - hdr_size) +
+ hdr_size;
+}
+
/**
* pmcraid_notify_ccn - notifies about CCN event msg to user space
* @pinstance: pointer adapter instance structure
@@ -1460,10 +1471,10 @@ static int pmcraid_notify_aen(
*/
static int pmcraid_notify_ccn(struct pmcraid_instance *pinstance)
{
- return pmcraid_notify_aen(pinstance,
- pinstance->ccn.msg,
- le32_to_cpu(pinstance->ccn.hcam->data_len) +
- sizeof(struct pmcraid_hcam_hdr));
+ u32 data_size = pmcraid_hcam_data_size(pinstance->ccn.hcam->data_len,
+ sizeof(struct pmcraid_hcam_ccn_ext));
+
+ return pmcraid_notify_aen(pinstance, pinstance->ccn.msg, data_size);
}
/**
@@ -1475,10 +1486,10 @@ static int pmcraid_notify_ccn(struct pmcraid_instance *pinstance)
*/
static int pmcraid_notify_ldn(struct pmcraid_instance *pinstance)
{
- return pmcraid_notify_aen(pinstance,
- pinstance->ldn.msg,
- le32_to_cpu(pinstance->ldn.hcam->data_len) +
- sizeof(struct pmcraid_hcam_hdr));
+ u32 data_size = pmcraid_hcam_data_size(pinstance->ldn.hcam->data_len,
+ sizeof(struct pmcraid_hcam_ldn));
+
+ return pmcraid_notify_aen(pinstance, pinstance->ldn.msg, data_size);
}
/**
--
2.43.0