[PATCH] scsi: snic: reject a target count larger than the response buffer

From: Yehyeong Lee

Date: Sun Oct 18 2026 - 10:00:04 EST


snic_queue_report_tgt_req() sizes the REPORT TARGETS response buffer for
min(fwinfo.max_tgts, shost->max_id) entries. The completion handler walks
that buffer for as many entries as the adapter reports in tgt_cnt, and the
only thing in the way is

SNIC_BUG_ON(tgt_cnt > snic->fwinfo.max_tgts);

which compares against the adapter's exchange-version value rather than
the bound the allocation was built with, and which is a WARN_ON_ONCE in
any build without DEBUG, so it falls through into the walk. An adapter
reporting more targets than were asked for reads past the buffer, and the
count is also stored for snic_handle_tgt_disc() to walk a second time and
create a target per entry.

The same exchange-version handler already clamps max_sgs_per_cmd against a
driver limit; max_tgts is taken as it arrives.

Compare the reported count against the bound the request was built with,
and fail the completion the way an empty target list is already failed.

I have no Cisco VIC hardware; the completion is injected under a KUnit
harness so that the adapter reports 259 targets for a 256-entry request.
The W taint below is the UML test machine's own virtio_pcidev warning:

BUG: KASAN: slab-out-of-bounds in snic_report_tgt_cmpl_handler+0x266/0x410
Read of size 4 at addr 00000000622c0810 by task kunit_try_catch/20

CPU: 0 UID: 0 PID: 20 Comm: kunit_try_catch Tainted: G W N 7.3.0-rc7-g58161ead29e5-dirty #7 VOLUNTARY
Tainted: [W]=WARN, [N]=TEST
Stack:
60d4e7dc 6220f200 622c20d8 00000000
ffffff00 60d4e7dc 60d56045 622c0810
60dcd680 6009aac3 622cfce0 6003e621
Call Trace:
[<6009aac3>] ? dump_stack_lvl+0x5e/0x7a
[<6003e621>] ? _printk+0x0/0xd7
[<6004b21d>] ? print_report+0x14b/0x517
[<603bdf3b>] ? kasan_save_track+0x1b/0x40
[<6003e621>] ? _printk+0x0/0xd7
[<600897a3>] ? snic_report_tgt_cmpl_handler+0x266/0x410
[<603beebb>] ? kasan_report+0x11b/0x160
[<600897a3>] ? snic_report_tgt_cmpl_handler+0x266/0x410
[<60073dad>] ? _dev_printk+0x0/0xe8
[<600897a3>] ? snic_report_tgt_cmpl_handler+0x266/0x410
[<6008a11c>] ? snic_lt_silent_overrun.cold+0x46/0x4da
[<6089d880>] ? snic_lt_silent_overrun+0x0/0x330
[<600bf62d>] ? os_nsecs+0x2d/0x40
[<600a16a4>] ? timer_read+0x14/0x30
[<602235de>] ? ktime_get_ts64+0x8e/0x2c0
[<60223550>] ? ktime_get_ts64+0x0/0x2c0
[<606fa06c>] ? kunit_try_run_case+0x1bc/0x310
[<606f9eb0>] ? kunit_try_run_case+0x0/0x310
[<603c08f0>] ? __kasan_check_read+0x0/0x20
[<600bf020>] ? um_set_signals+0x0/0x60
[<600bf020>] ? um_set_signals+0x0/0x60
[<6013e3cd>] ? __kthread_parkme+0xdd/0x1c0
[<606f9eb0>] ? kunit_try_run_case+0x0/0x310
[<60700130>] ? kunit_generic_run_threadfn_adapter+0x0/0x100
[<607001ac>] ? kunit_generic_run_threadfn_adapter+0x7c/0x100
[<6014464e>] ? kthread+0x36e/0x560
[<601442e0>] ? kthread+0x0/0x560
[<6009f0de>] ? new_thread_handler+0xce/0x130

The buggy address belongs to the object at 00000000622c0000
which belongs to the cache kmalloc-4k of size 4096
The buggy address is located 0 bytes to the right of
allocated 2064-byte region [00000000622c0000, 00000000622c0810)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x22c0
head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0x40(head|zone=0)
page_type: f5(slab)
raw: 0000000000000040 0000000061402140 0000000000000122 0000000000000000
raw: 0000000000000000 0000000000040004 00000000f5000000
head: 0000000000000040 0000000061402140 0000000000000122 0000000000000000
head: 0000000000000000 0000000000040004 00000000f5000000 0000000000000003
head: 000000009f279a01 00000000ffffffff 00000000ffffffff 0000000000000000
head: 0000000000000000 00000000ffffffff
page dumped because: kasan: bad access detected

Memory state around the buggy address:
00000000622c0700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000000622c0780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>00000000622c0800: 00 00 fc fc fc fc fc fc fc fc fc fc fc fc fc fc
^
00000000622c0880: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
00000000622c0900: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc

Fixes: c8806b6c9e82 ("snic: driver for Cisco SCSI HBA")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Yehyeong Lee <yhlee@xxxxxxxxxxxxxxxxxx>
---
drivers/scsi/snic/snic_disc.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/snic/snic_disc.c b/drivers/scsi/snic/snic_disc.c
index 71d34a702f2ab..df7da6413f84a 100644
--- a/drivers/scsi/snic/snic_disc.c
+++ b/drivers/scsi/snic/snic_disc.c
@@ -385,7 +385,7 @@ snic_report_tgt_cmpl_handler(struct snic *snic, struct snic_fw_req *fwreq)
{

u8 typ, cmpl_stat;
- u32 cmnd_id, hid, tgt_cnt = 0;
+ u32 cmnd_id, hid, tgt_cnt = 0, ntgts;
ulong ctx;
struct snic_req_info *rqi = NULL;
struct snic_tgt_id *tgtid;
@@ -406,7 +406,19 @@ snic_report_tgt_cmpl_handler(struct snic *snic, struct snic_fw_req *fwreq)
/* printing list of targets here */
SNIC_HOST_INFO(snic->shost, "Target Count = %d\n", tgt_cnt);

- SNIC_BUG_ON(tgt_cnt > snic->fwinfo.max_tgts);
+ if (snic->fwinfo.max_tgts)
+ ntgts = min_t(u32, snic->fwinfo.max_tgts, snic->shost->max_id);
+ else
+ ntgts = snic->shost->max_id;
+
+ if (tgt_cnt > ntgts) {
+ SNIC_HOST_ERR(snic->shost,
+ "Target count %u exceeds the %u requested.\n",
+ tgt_cnt, ntgts);
+ ret = 1;
+
+ goto end;
+ }

for (i = 0; i < tgt_cnt; i++)
SNIC_HOST_INFO(snic->shost,
--
2.43.0