Linux RDMA and InfiniBand development
 help / color / mirror / Atom feed
* [PATCH v3 0/2] RDMA/srp: bound the receive IU the target asks for
@ 2026-11-02  6:19 Yehyeong Lee
  2026-11-02  6:19 ` [PATCH v3 1/2] RDMA/srp: refuse a target that cannot receive an SRP_RSP Yehyeong Lee
  2026-11-02  6:19 ` [PATCH v3 2/2] RDMA/srp: do not DMA-sync a receive IU past its mapped length Yehyeong Lee
  0 siblings, 2 replies; 5+ messages in thread
From: Yehyeong Lee @ 2026-11-02  6:19 UTC (permalink / raw)
  To: Bart Van Assche
  Cc: Leon Romanovsky, Jason Gunthorpe, linux-rdma, linux-kernel,
	stable, yhlee

The target decides how large the initiator's receive buffers are, and the
initiator never checks the answer.

srp_cm_rep_handler() takes max_ti_iu_len out of the SRP_LOGIN_RSP and
srp_alloc_iu_bufs() sizes every receive IU with it. The first patch refuses
a login that reports less than an SRP_RSP, because such a login hands the
receive path undersized buffers, and a report of zero is worse: kzalloc()
answers it with ZERO_SIZE_PTR, which ib_dma_map_single() accepts on a
virtually mapped transport without looking at the length.

The second patch stops srp_recv_done() from syncing those buffers with
ch->max_ti_iu_len. The receive ring is allocated once and kept across a
reconnect while max_ti_iu_len is taken from every login response, so a
target that reports a larger value the second time around makes the driver
sync past the end of the mapping. iu->size is the length that was mapped,
and the length srp_post_recv() posts.

v2 -> v3: commit message of 1/2 only. The KASAN report now comes from
a real rxe connection instead of a KUnit harness. No code changes.
This is the repost after the merge window that Bart asked for.
v2 RESEND: https://lore.kernel.org/r/20261026055430.406487-1-yhlee@isslab.korea.ac.kr

Changes since v1:
1/2 unchanged. Dropped v1 2/2 (drop a truncated SRP_RSP): the floor makes
the buffer always >= sizeof(srp_rsp) so there is no out-of-bounds read, and
dropping the response would lose its req_lim_delta credit (per review). New
2/2 bounds the two srp_recv_done() DMA syncs to iu->size, the reconnect
case review noted 1/2 did not cover.

Yehyeong Lee (2):
  RDMA/srp: refuse a target that cannot receive an SRP_RSP
  RDMA/srp: do not DMA-sync a receive IU past its mapped length

 drivers/infiniband/ulp/srp/ib_srp.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)


base-commit: 6628e7d4c6b25c8d18f1345e3a20d21829aae7e4
-- 
2.43.0


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

* [PATCH v3 1/2] RDMA/srp: refuse a target that cannot receive an SRP_RSP
  2026-11-02  6:19 [PATCH v3 0/2] RDMA/srp: bound the receive IU the target asks for Yehyeong Lee
@ 2026-11-02  6:19 ` Yehyeong Lee
  2026-11-02  6:31   ` sashiko-bot
  2026-11-02  6:19 ` [PATCH v3 2/2] RDMA/srp: do not DMA-sync a receive IU past its mapped length Yehyeong Lee
  1 sibling, 1 reply; 5+ messages in thread
From: Yehyeong Lee @ 2026-11-02  6:19 UTC (permalink / raw)
  To: Bart Van Assche
  Cc: Leon Romanovsky, Jason Gunthorpe, linux-rdma, linux-kernel,
	stable, yhlee

srp_cm_rep_handler() takes max_ti_iu_len straight from the target's
SRP_LOGIN_RSP and srp_alloc_iu_bufs() then sizes every receive IU with it,
so the target alone decides how large the initiator's receive buffers are.
Nothing enforces a lower bound.

The initiator parses a 36 byte header out of those buffers. A target that
reports a smaller max_ti_iu_len gets undersized buffers, and the header
reads in srp_process_rsp() then run past the allocation. A report of zero
is worse, because kzalloc() answers it with ZERO_SIZE_PTR, and on a
transport that maps addresses virtually ib_dma_map_single() returns that
pointer without looking at the length and ib_dma_mapping_error() reports
success, so the buffer reaches srp_recv_done() and the read of the opcode
dereferences ZERO_SIZE_PTR.

Refuse the login instead. Both the largest messages the initiator parses,
SRP_RSP and SRP_AER_REQ, are 36 bytes, and a target that cannot send one
cannot speak the protocol, so nothing that works today is turned away.

Reproduced over rxe with ib_srpt modified to advertise a max_ti_iu_len of
33 and to send its first SRP_RSP as 33 bytes with SRP_RSP_FLAG_SNSVALID
set, which is what makes srp_process_rsp() read resp_data_len at offset
32. A report of zero ends in a general protection fault on the opcode read
instead. With this patch both logins are refused.

  BUG: KASAN: slab-out-of-bounds in srp_recv_done+0x8e5/0x1c80
  Read of size 4 at addr ffff888106046aa0 by task kworker/u8:2/42

  CPU: 1 UID: 0 PID: 42 Comm: kworker/u8:2 Not tainted 7.4.0-rc1-SRPFLRA-00001-gc23c1c890846 #7 PREEMPT(lazy)
  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
  Workqueue: rxe_wq do_work
  Call Trace:
   <IRQ>
   dump_stack_lvl+0x53/0x70
   print_report+0xd0/0x630
   ? __pfx__raw_spin_lock_irqsave+0x10/0x10
   ? srp_recv_done+0x8e5/0x1c80
   kasan_report+0xce/0x100
   ? srp_recv_done+0x8e5/0x1c80
   srp_recv_done+0x8e5/0x1c80
   ? __pfx_srp_recv_done+0x10/0x10
   ? rxe_poll_cq+0x253/0x3d0
   __ib_process_cq+0xe1/0x390
   ib_poll_handler+0x6e/0x200
   irq_poll_softirq+0x1df/0x480
   ? __pfx_irq_poll_softirq+0x10/0x10
   handle_softirqs+0x1b3/0x600
   ? __pfx_handle_softirqs+0x10/0x10
   do_softirq+0x3d/0x60
   </IRQ>
   <TASK>
   __local_bh_enable_ip+0x6a/0x70
   __alloc_skb+0x734/0x890
   ? _raw_spin_lock_irqsave+0x86/0xe0
   ? __pfx___alloc_skb+0x10/0x10
   ? _raw_read_unlock_irqrestore+0x16/0x50
   rxe_init_packet+0x16b/0x5c0
   prepare_ack_packet+0xc6/0x8a0
   rxe_receiver+0x499/0x9a20
   ? __pfx_rxe_receiver+0x10/0x10
   ? rxe_completer+0x29e5/0x38c0
   ? __pfx__raw_spin_lock_irqsave+0x10/0x10
   ? __pfx_rxe_receiver+0x10/0x10
   do_work+0x144/0x470
   process_one_work+0x697/0x1060
   ? __pfx___schedule+0x10/0x10
   ? __pfx_process_one_work+0x10/0x10
   ? _raw_spin_lock_irq+0x81/0xe0
   ? __pfx_do_work+0x10/0x10
   ? assign_work+0x11d/0x370
   worker_thread+0x45b/0xd10
   ? __pfx_worker_thread+0x10/0x10
   kthread+0x2c8/0x3b0
   ? recalc_sigpending+0x15c/0x1e0
   ? __pfx_kthread+0x10/0x10
   ret_from_fork+0x36e/0x5a0
   ? __pfx_ret_from_fork+0x10/0x10
   ? __switch_to+0x572/0xdc0
   ? __pfx_kthread+0x10/0x10
   ret_from_fork_asm+0x1a/0x30
   </TASK>

  Allocated by task 9:
   kasan_save_stack+0x33/0x60
   kasan_save_track+0x14/0x30
   __kasan_kmalloc+0x8f/0xa0
   __kmalloc_noprof+0x193/0x450
   srp_alloc_iu.constprop.0+0x69/0x5c0
   srp_cm_rep_handler+0xc4a/0x1bd0
   srp_rdma_cm_handler+0x111/0x7f0
   cma_cm_event_handler+0x3e/0x240
   cma_ib_handler+0x190/0x750
   cm_process_work+0x41/0x330
   cm_work_handler+0x1de2/0xc160
   process_one_work+0x697/0x1060
   worker_thread+0x45b/0xd10
   kthread+0x2c8/0x3b0
   ret_from_fork+0x36e/0x5a0
   ret_from_fork_asm+0x1a/0x30

  The buggy address belongs to the object at ffff888106046a80
   which belongs to the cache kmalloc-64 of size 64
  The buggy address is located 32 bytes inside of
   allocated 33-byte region [ffff888106046a80, ffff888106046aa1)

Fixes: aef9ec39c47f ("IB: Add SCSI RDMA Protocol (SRP) initiator")
Cc: stable@vger.kernel.org
Signed-off-by: Yehyeong Lee <yhlee@isslab.korea.ac.kr>
---
 drivers/infiniband/ulp/srp/ib_srp.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 5811f02df98053..a85d28b95306a5 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -2379,6 +2379,13 @@ static void srp_cm_rep_handler(struct ib_cm_id *cm_id,
 
 	if (lrsp->opcode == SRP_LOGIN_RSP) {
 		ch->max_ti_iu_len = be32_to_cpu(lrsp->max_ti_iu_len);
+		if (ch->max_ti_iu_len < sizeof(struct srp_rsp)) {
+			shost_printk(KERN_ERR, target->scsi_host, PFX
+				     "Target reported max_ti_iu_len %u, too small for a %zu byte SRP_RSP\n",
+				     ch->max_ti_iu_len, sizeof(struct srp_rsp));
+			ret = -ECONNRESET;
+			goto error;
+		}
 		ch->req_lim       = be32_to_cpu(lrsp->req_lim_delta);
 		ch->use_imm_data  = srp_use_imm_data &&
 			(lrsp->rsp_flags & SRP_LOGIN_RSP_IMMED_SUPP);
-- 
2.43.0


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

* [PATCH v3 2/2] RDMA/srp: do not DMA-sync a receive IU past its mapped length
  2026-11-02  6:19 [PATCH v3 0/2] RDMA/srp: bound the receive IU the target asks for Yehyeong Lee
  2026-11-02  6:19 ` [PATCH v3 1/2] RDMA/srp: refuse a target that cannot receive an SRP_RSP Yehyeong Lee
@ 2026-11-02  6:19 ` Yehyeong Lee
  2026-11-02  6:30   ` sashiko-bot
  1 sibling, 1 reply; 5+ messages in thread
From: Yehyeong Lee @ 2026-11-02  6:19 UTC (permalink / raw)
  To: Bart Van Assche
  Cc: Leon Romanovsky, Jason Gunthorpe, linux-rdma, linux-kernel,
	stable, yhlee

srp_recv_done() syncs the receive IU with ch->max_ti_iu_len, but the IU
was mapped with iu->size.  Those are the same value only until the first
reconnect.  srp_cm_rep_handler() takes ch->max_ti_iu_len from every
SRP_LOGIN_RSP while it allocates the receive ring only when there is none,
and srp_rport_reconnect() keeps the ring across a reconnect, so a target
that reports a larger max_ti_iu_len the second time around makes both
ib_dma_sync_single_for_cpu() and ib_dma_sync_single_for_device() run past
the end of the mapping, which breaks the DMA API rules.

The HCA itself cannot overrun the buffer, because srp_post_recv() posts
iu->size, so sync the length that was actually mapped.

Suggested-by: Bart Van Assche <bvanassche@acm.org>
Fixes: aef9ec39c47f ("IB: Add SCSI RDMA Protocol (SRP) initiator")
Cc: stable@vger.kernel.org
Signed-off-by: Yehyeong Lee <yhlee@isslab.korea.ac.kr>
---
 drivers/infiniband/ulp/srp/ib_srp.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index a85d28b95306a5..159d6b6aa93e3a 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -2111,7 +2111,7 @@ static void srp_recv_done(struct ib_cq *cq, struct ib_wc *wc)
 		return;
 	}
 
-	ib_dma_sync_single_for_cpu(dev, iu->dma, ch->max_ti_iu_len,
+	ib_dma_sync_single_for_cpu(dev, iu->dma, iu->size,
 				   DMA_FROM_DEVICE);
 
 	opcode = *(u8 *) iu->buf;
@@ -2148,7 +2148,7 @@ static void srp_recv_done(struct ib_cq *cq, struct ib_wc *wc)
 		break;
 	}
 
-	ib_dma_sync_single_for_device(dev, iu->dma, ch->max_ti_iu_len,
+	ib_dma_sync_single_for_device(dev, iu->dma, iu->size,
 				      DMA_FROM_DEVICE);
 
 	res = srp_post_recv(ch, iu);
-- 
2.43.0


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

* Re: [PATCH v3 2/2] RDMA/srp: do not DMA-sync a receive IU past its mapped length
  2026-11-02  6:19 ` [PATCH v3 2/2] RDMA/srp: do not DMA-sync a receive IU past its mapped length Yehyeong Lee
@ 2026-11-02  6:30   ` sashiko-bot
  0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-11-02  6:30 UTC (permalink / raw)
  To: Yehyeong Lee; +Cc: linux-rdma

> srp_recv_done() syncs the receive IU with ch->max_ti_iu_len, but the IU
> was mapped with iu->size.  Those are the same value only until the first
> reconnect.  srp_cm_rep_handler() takes ch->max_ti_iu_len from every
> SRP_LOGIN_RSP while it allocates the receive ring only when there is none,
> and srp_rport_reconnect() keeps the ring across a reconnect, so a target
> that reports a larger max_ti_iu_len the second time around makes both
> ib_dma_sync_single_for_cpu() and ib_dma_sync_single_for_device() run past
> the end of the mapping, which breaks the DMA API rules.
> 
> The HCA itself cannot overrun the buffer, because srp_post_recv() posts
> iu->size, so sync the length that was actually mapped.
> 
> Suggested-by: Bart Van Assche <bvanassche@acm.org>
> Fixes: aef9ec39c47f ("IB: Add SCSI RDMA Protocol (SRP) initiator")
> Cc: stable@vger.kernel.org
> Signed-off-by: Yehyeong Lee <yhlee@isslab.korea.ac.kr>

Sashiko has reviewed this patch and found no issues.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261102061938.617371-1-yhlee@isslab.korea.ac.kr?part=2


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

* Re: [PATCH v3 1/2] RDMA/srp: refuse a target that cannot receive an SRP_RSP
  2026-11-02  6:19 ` [PATCH v3 1/2] RDMA/srp: refuse a target that cannot receive an SRP_RSP Yehyeong Lee
@ 2026-11-02  6:31   ` sashiko-bot
  0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-11-02  6:31 UTC (permalink / raw)
  To: Yehyeong Lee; +Cc: linux-rdma

> srp_cm_rep_handler() takes max_ti_iu_len straight from the target's
> SRP_LOGIN_RSP and srp_alloc_iu_bufs() then sizes every receive IU with it,
> so the target alone decides how large the initiator's receive buffers are.
> Nothing enforces a lower bound.
> 
> The initiator parses a 36 byte header out of those buffers. A target that
> reports a smaller max_ti_iu_len gets undersized buffers, and the header
> reads in srp_process_rsp() then run past the allocation. A report of zero
> is worse, because kzalloc() answers it with ZERO_SIZE_PTR, and on a
> transport that maps addresses virtually ib_dma_map_single() returns that
> pointer without looking at the length and ib_dma_mapping_error() reports
> success, so the buffer reaches srp_recv_done() and the read of the opcode
> dereferences ZERO_SIZE_PTR.
> 
> Refuse the login instead. Both the largest messages the initiator parses,
> [ ... ]
>    allocated 33-byte region [ffff888106046a80, ffff888106046aa1)
> 
> Fixes: aef9ec39c47f ("IB: Add SCSI RDMA Protocol (SRP) initiator")
> Cc: stable@vger.kernel.org
> Signed-off-by: Yehyeong Lee <yhlee@isslab.korea.ac.kr>

Sashiko has reviewed this patch and found no issues.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261102061938.617371-1-yhlee@isslab.korea.ac.kr?part=1


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

end of thread, other threads:[~2026-11-02  6:31 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-02  6:19 [PATCH v3 0/2] RDMA/srp: bound the receive IU the target asks for Yehyeong Lee
2026-11-02  6:19 ` [PATCH v3 1/2] RDMA/srp: refuse a target that cannot receive an SRP_RSP Yehyeong Lee
2026-11-02  6:31   ` sashiko-bot
2026-11-02  6:19 ` [PATCH v3 2/2] RDMA/srp: do not DMA-sync a receive IU past its mapped length Yehyeong Lee
2026-11-02  6:30   ` sashiko-bot

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