[PATCH v4 1/2] RDMA/srpt: bound the indirect descriptor table to the IU
From: Yehyeong Lee
Date: Sat Oct 24 2026 - 12:32:43 EST
srpt_get_desc_tbl() takes the number of INDIRECT descriptors from
idb->table_desc.len, which the initiator controls, and checks it only
against data_out_desc_cnt + data_in_desc_cnt, two more initiator fields.
Both are u8, so the pair admits up to 510 descriptors, and nothing
compares the table against the receive IU it has to live in.
srpt_alloc_rw_ctxs() then walks idb->desc_list for that many entries.
With the default srp_max_req_size of 8276 the table fits as long as the
additional CDB is short, but ADDITIONAL CDB LENGTH is an initiator field
too, and at its maximum of 252 bytes 510 descriptors end at
48 + 252 + 20 + 510 * 16 = 8480, which is past the end of the object:
BUG: KASAN: slab-out-of-bounds in srpt_alloc_rw_ctxs+0x660/0x860
Read of size 4 at addr ffff888002d6a05c by task kunit_try_catch/43
CPU: 0 UID: 0 PID: 43 Comm: kunit_try_catch Tainted: G N 7.3.0-11999-g5b0764a53235-dirty #1 PREEMPT(lazy)
Tainted: [N]=TEST
Call Trace:
<TASK>
dump_stack_lvl+0x3f/0x50
print_report+0xcd/0x620
? alloc_pages_node_noprof+0xa2/0x140
? srpt_alloc_rw_ctxs+0x660/0x860
kasan_report+0xde/0x110
? srpt_alloc_rw_ctxs+0x660/0x860
srpt_alloc_rw_ctxs+0x660/0x860
? __dequeue_entity+0xb12/0x1ba0
srpt_test_run.constprop.0+0x135/0xc50
? __pfx_srpt_test_run.constprop.0+0x10/0x10
? pick_task_fair+0x126/0x1950
? update_curr.constprop.0+0x4a/0x390
? __set_cpus_allowed_ptr+0x181/0x240
? __pfx_read_tsc+0x10/0x10
? ktime_get_ts64+0x192/0x250
kunit_try_run_case+0x1ca/0x4b0
? __pfx_kunit_try_run_case+0x10/0x10
? kthread_affine_node+0x24b/0x370
? __pfx_kthread_affine_node+0x10/0x10
? __pfx_kunit_try_run_case+0x10/0x10
? __pfx_kunit_generic_run_threadfn_adapter+0x10/0x10
kunit_generic_run_threadfn_adapter+0x7b/0xe0
kthread+0x36e/0x500
? __pfx_kthread+0x10/0x10
ret_from_fork+0x34d/0x620
? __pfx_ret_from_fork+0x10/0x10
? __switch_to+0x22/0xdd0
? __pfx_kthread+0x10/0x10
ret_from_fork_asm+0x19/0x30
</TASK>
Allocated by task 43:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
__kasan_slab_alloc+0x6e/0x70
kmem_cache_alloc_noprof+0xfc/0x2b0
srpt_test_ctx_init.constprop.0+0x481/0xfa0
srpt_test_run.constprop.0+0xf1/0xc50
kunit_try_run_case+0x1ca/0x4b0
kunit_generic_run_threadfn_adapter+0x7b/0xe0
kthread+0x36e/0x500
ret_from_fork+0x34d/0x620
ret_from_fork_asm+0x19/0x30
The buggy address belongs to the object at ffff888002d68000
which belongs to the cache srpt-kunit-iu of size 8276
The buggy address is located 8 bytes to the right of
allocated 8276-byte region [ffff888002d68000, ffff888002d6a054)
The KUnit harness that forces this is not part of this patch.
Compare the span the table occupies, which is the table offset plus the
descriptor header plus nbufs descriptors, against byte_len directly. A
short IU that cannot hold even the header is refused, and so is a
table_desc.len below one descriptor, with no division and no dependence on
a sign. nbufs is at most 510 once the existing count check has passed, so
the multiplication cannot overflow.
The header always lies inside the allocated buffer, since the largest
offset srpt_get_desc_buf() can return is 48 + 252 and the header is 20
bytes, so it ends at 320 while srp_max_req_size is at least
MIN_MAX_REQ_SIZE, which is 996. It does not always lie inside the bytes the
initiator actually sent, which is why the span starts at the table offset
and covers the header as well.
Fixes: a42d985bd5b2 ("ib_srpt: Initial SRP Target merge for v3.3-rc1")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Yehyeong Lee <yhlee@xxxxxxxxxxxxxxxxxx>
---
drivers/infiniband/ulp/srpt/ib_srpt.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index 43c3ff1ad8e7e..21264264356a2 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -1117,6 +1117,7 @@ static int srpt_get_desc_tbl(struct srpt_recv_ioctx *recv_ioctx,
struct srp_indirect_buf *idb = srpt_get_desc_buf(srp_cmd);
int nbufs = be32_to_cpu(idb->table_desc.len) /
sizeof(struct srp_direct_buf);
+ size_t desc_off = (uintptr_t)idb - (uintptr_t)srp_cmd;
if (nbufs >
(srp_cmd->data_out_desc_cnt + srp_cmd->data_in_desc_cnt)) {
@@ -1128,6 +1129,14 @@ static int srpt_get_desc_tbl(struct srpt_recv_ioctx *recv_ioctx,
return -EINVAL;
}
+ if (desc_off + sizeof(*idb) +
+ (size_t)nbufs * sizeof(struct srp_direct_buf) >
+ (size_t)recv_ioctx->byte_len) {
+ pr_err("received SRP_CMD indirect table (%d descriptors) that does not fit the %d-byte IU\n",
+ nbufs, recv_ioctx->byte_len);
+ return -EINVAL;
+ }
+
*data_len = be32_to_cpu(idb->len);
return srpt_alloc_rw_ctxs(ioctx, idb->desc_list, nbufs,
sg, sg_cnt);
--
2.43.0