* [PATCH net] RDS/IB: validate receive completion payload length
@ 2026-10-06 20:52 sungbyeongchan
2026-10-06 20:55 ` netdev-bot+sinfo
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: sungbyeongchan @ 2026-10-06 20:52 UTC (permalink / raw)
To: Allison Henderson, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Andy Grover
Cc: netdev, linux-rdma, rds-devel, linux-kernel
An RDS/RDMA peer can declare a fragment length larger than the payload
reported by the receive completion. The receive path attaches the recycled
receive fragment without validating those lengths, allowing recvmsg() to
return stale bytes beyond the actual payload.
Validate data_len against the expected current-fragment length before
transferring fragment ownership. Disconnect and reconnect on mismatch.
The issue reproduced in two clean QEMU boots. A peer declared 4096 bytes
while posting only 16 bytes, and a receiver under a different UID obtained
4080-byte tails from prior messages in all 256 attempts in each boot. With
this change, the malformed message was not delivered, reconnection
succeeded, and a subsequent normal 4096-byte message was delivered intact.
Fixes: 1e23b3ee0e94 ("RDS/IB: Receive datagrams via IB")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: sungbyeongchan <tjdqudcks0424@naver.com>
---
net/rds/ib_recv.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c
index bd6cb3ffaa571..0daddb108c8a7 100644
--- a/net/rds/ib_recv.c
+++ b/net/rds/ib_recv.c
@@ -949,6 +949,15 @@ static void rds_ib_process_recv(struct rds_connection *conn,
}
}
+ if (data_len != min_t(u32, ic->i_recv_data_rem, RDS_FRAG_SIZE)) {
+ rds_ib_conn_error(conn,
+ "incoming fragment payload length %u, expected %u; "
+ "disconnecting and reconnecting\n",
+ data_len,
+ min_t(u32, ic->i_recv_data_rem, RDS_FRAG_SIZE));
+ goto done;
+ }
+
list_add_tail(&recv->r_frag->f_item, &ibinc->ii_frags);
recv->r_frag = NULL;
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH net] RDS/IB: validate receive completion payload length
2026-10-06 20:52 [PATCH net] RDS/IB: validate receive completion payload length sungbyeongchan
@ 2026-10-06 20:55 ` netdev-bot+sinfo
2026-10-07 1:13 ` Allison Henderson
2026-10-09 11:52 ` netdev-bot+sashiko
2 siblings, 0 replies; 4+ messages in thread
From: netdev-bot+sinfo @ 2026-10-06 20:55 UTC (permalink / raw)
To: sungbyeongchan
Cc: Allison Henderson, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Andy Grover, netdev, linux-rdma,
rds-devel, linux-kernel
Hi!
This is an automated message. This series looks like a fix, but its
commit messages seem to be missing some information:
- How the issue was discovered, e.g. hit in production, hit during
development, syzbot report, manual code inspection, LLM or static
analysis tool scan.
Please do not repost the series just to address the above. Instead,
reply to this email with the missing information, so that reviewers
can take it into account. If the series needs another revision for
other reasons, please include the information in the commit messages
then.
The evaluation is done by an LLM so it may be wrong, if you think
that is the case please reply and explain.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH net] RDS/IB: validate receive completion payload length
2026-10-06 20:52 [PATCH net] RDS/IB: validate receive completion payload length sungbyeongchan
2026-10-06 20:55 ` netdev-bot+sinfo
@ 2026-10-07 1:13 ` Allison Henderson
2026-10-09 11:52 ` netdev-bot+sashiko
2 siblings, 0 replies; 4+ messages in thread
From: Allison Henderson @ 2026-10-07 1:13 UTC (permalink / raw)
To: sungbyeongchan, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Andy Grover
Cc: netdev, linux-rdma, rds-devel, linux-kernel
On Wed, 2026-10-07 at 05:52 +0900, sungbyeongchan wrote:
> An RDS/RDMA peer can declare a fragment length larger than the payload
> reported by the receive completion. The receive path attaches the recycled
> receive fragment without validating those lengths, allowing recvmsg() to
> return stale bytes beyond the actual payload.
>
> Validate data_len against the expected current-fragment length before
> transferring fragment ownership. Disconnect and reconnect on mismatch.
>
> The issue reproduced in two clean QEMU boots. A peer declared 4096 bytes
> while posting only 16 bytes, and a receiver under a different UID obtained
> 4080-byte tails from prior messages in all 256 attempts in each boot. With
> this change, the malformed message was not delivered, reconnection
> succeeded, and a subsequent normal 4096-byte message was delivered intact.
>
> Fixes: 1e23b3ee0e94 ("RDS/IB: Receive datagrams via IB")
> Cc: stable@vger.kernel.org
> Assisted-by: LLM
> Signed-off-by: sungbyeongchan <tjdqudcks0424@naver.com>
Hi Sungbyeongchan,
Thanks for sending this, and for following up on the earlier feedback so
quickly. However, I realized after I sent it that another contributor had
already publicly sent an equivalent fix earlier today, and the convention is
to take the first correct patch on the list.
https://lore.kernel.org/netdev/20261006125720.81227-1-shubham@octane.security/
So no need to follow up with the sashiko review, and I apologize for the
miss-communication, but I will ask your Reported-by tag to be applied since you
were the first to report the same bug. This was a solid find, and the reproduction
was very well done. Please continue to send RDS fixes as you find them.
Thank you!
Allison
> ---
> net/rds/ib_recv.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c
> index bd6cb3ffaa571..0daddb108c8a7 100644
> --- a/net/rds/ib_recv.c
> +++ b/net/rds/ib_recv.c
> @@ -949,6 +949,15 @@ static void rds_ib_process_recv(struct rds_connection *conn,
> }
> }
>
> + if (data_len != min_t(u32, ic->i_recv_data_rem, RDS_FRAG_SIZE)) {
> + rds_ib_conn_error(conn,
> + "incoming fragment payload length %u, expected %u; "
> + "disconnecting and reconnecting\n",
> + data_len,
> + min_t(u32, ic->i_recv_data_rem, RDS_FRAG_SIZE));
> + goto done;
> + }
> +
> list_add_tail(&recv->r_frag->f_item, &ibinc->ii_frags);
> recv->r_frag = NULL;
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH net] RDS/IB: validate receive completion payload length
2026-10-06 20:52 [PATCH net] RDS/IB: validate receive completion payload length sungbyeongchan
2026-10-06 20:55 ` netdev-bot+sinfo
2026-10-07 1:13 ` Allison Henderson
@ 2026-10-09 11:52 ` netdev-bot+sashiko
2 siblings, 0 replies; 4+ messages in thread
From: netdev-bot+sashiko @ 2026-10-09 11:52 UTC (permalink / raw)
To: tjdqudcks0424
Cc: achender, davem, edumazet, kuba, pabeni, horms, andy.grover,
netdev, linux-rdma, rds-devel, linux-kernel
Thank you for your contribution! Sashiko AI review found 3 potential
issue(s) to consider.
Critical: 0 · High: 1 · Medium: 1 · Low: 1
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [High] The new length check can be bypassed, so the stale/uninitialized
receive-fragment disclosure that this commit claims to close can still…
- [Medium] When the new length check in rds_ib_process_recv()
(net/rds/ib_recv.c:952-959) rejects a fragment, it jumps to `done` and…
- [Low] The commit message understates the impact.
--
RDS/IB: validate receive completion payload length
This patch adds a check to rds_ib_process_recv(). The payload length
reported by the receive completion must match the expected length of the
current fragment, min(i_recv_data_rem, RDS_FRAG_SIZE). On mismatch the
connection is dropped and reconnected, and the receive fragment is not
attached to the incoming message.
> An RDS/RDMA peer can declare a fragment length larger than the payload
> reported by the receive completion. The receive path attaches the recycled
> receive fragment without validating those lengths, allowing recvmsg() to
> return stale bytes beyond the actual payload.
[Severity: Low]
Is "recycled receive fragment" the full picture here? When
ic->i_cache_frags is empty, rds_ib_refill_one_frag() allocates a new
page:
net/rds/ib_recv.c:rds_ib_refill_one_frag() {
...
ret = rds_page_remainder_alloc(&frag->f_sg,
RDS_FRAG_SIZE, page_mask);
...
}
page_mask is either GFP_HIGHUSER or the caller's gfp.
rds_page_remainder_alloc() then calls alloc_page() without __GFP_ZERO:
net/rds/page.c:rds_page_remainder_alloc() {
...
if (bytes >= PAGE_SIZE) {
page = alloc_page(gfp);
...
}
On a fresh frag, the bytes after a short payload would be uninitialized
kernel page contents, not only tails from earlier RDS messages.
The code change covers this case too. Could the commit message also
describe it as a kernel memory disclosure?
> diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c
> index bd6cb3ffaa571..0daddb108c8a7 100644
> --- a/net/rds/ib_recv.c
> +++ b/net/rds/ib_recv.c
> @@ -949,6 +949,15 @@ static void rds_ib_process_recv(struct rds_connection *conn,
> }
> }
>
> + if (data_len != min_t(u32, ic->i_recv_data_rem, RDS_FRAG_SIZE)) {
[Severity: High]
Can an RDMA write with immediate get past this check?
rds_ib_recv_cqe_handler() passes every successful completion to
rds_ib_process_recv() without checking wc->opcode:
net/rds/ib_recv.c:rds_ib_recv_cqe_handler() {
...
if (wc->status == IB_WC_SUCCESS) {
rds_ib_process_recv(conn, recv, wc->byte_len, state);
...
}
A write with immediate uses up the next receive WQE but does not write
to its scatter list (ic->i_recv_hdrs[slot] and recv->r_frag). For
IB_WC_RECV_RDMA_WITH_IMM, byte_len is the RDMA write length. In rxe,
for example:
drivers/infiniband/sw/rxe/rxe_resp.c:do_complete() {
...
wc->byte_len = (pkt->mask & RXE_IMMDT_MASK &&
pkt->mask & RXE_WRITE_MASK) ?
qp->resp.length : wqe->dma.length - wqe->dma.resid;
...
}
The header buffer for a ring slot is never cleared between uses. It
still holds the last normal header received into that slot, and that
header's checksum still verifies.
recv->r_frag is either a recycled frag from the cache or a fresh
alloc_page() page.
rds_ib_post_reg_frmr() registers RDS MRs with IB_ACCESS_REMOTE_WRITE. A
peer holding an rkey from a local RDS user could then do this:
1. send a normal message into a slot with h_len=4096, a bound dport,
and RDS_FLAG_RETRANSMITTED clear
2. when that slot comes around again, issue a write with immediate of
sizeof(struct rds_header) + 4096 bytes to a remote-writable MR
The new check sees data_len == min(i_recv_data_rem, RDS_FRAG_SIZE) and
passes, so the unwritten frag is attached.
rds_recv_incoming() only drops old sequence numbers when
RDS_FLAG_RETRANSMITTED is set:
net/rds/recv.c:rds_recv_incoming() {
...
if (be64_to_cpu(inc->i_hdr.h_sequence) < cp->cp_next_rx_seq &&
(inc->i_hdr.h_flags & RDS_FLAG_RETRANSMITTED)) {
...
}
rds_ib_inc_copy_to_user() would then copy h_len bytes of stale or
uninitialized frag data to userspace.
Should completions whose opcode is not IB_WC_RECV be rejected before the
receive buffers are parsed or byte_len is trusted?
> + rds_ib_conn_error(conn,
> + "incoming fragment payload length %u, expected %u; "
> + "disconnecting and reconnecting\n",
> + data_len,
> + min_t(u32, ic->i_recv_data_rem, RDS_FRAG_SIZE));
> + goto done;
> + }
[Severity: Medium]
Does this goto done leave the partial message in place for later
fragments to complete?
ic->i_ibinc stays set (it was just installed if this fragment started
the message), and ic->i_recv_data_rem is not reduced.
rds_ib_conn_error() ends up in rds_conn_path_drop(). That function only
sets RDS_CONN_ERROR and queues the shutdown work:
net/rds/connection.c:rds_conn_path_drop() {
...
atomic_set(&cp->cp_state, RDS_CONN_ERROR);
...
queue_work(cp->cp_wq, &cp->cp_down_w);
...
}
In the meantime poll_rcq() keeps calling rds_ib_recv_cqe_handler() for
the rest of the batch. Later tasklet runs do the same until shutdown
sets i_cq_quiesce.
A later fragment with the same h_sequence, h_len and ports, and the
expected length, passes both the header comparison and the new check.
For example, with h_len=8192 and these completions:
A: 4096 bytes -> attached, rem = 4096
B: 16 bytes -> rejected here, rem still 4096
C: 4096 bytes -> attached, rem = 0
The message is delivered as A+C, with C's payload where B's belongs.
rds_recv_incoming() does not check the connection error state. The
message is queued to the socket and acked through state->ack_next, and
cp_next_rx_seq advances. A later retransmission flagged
RDS_FLAG_RETRANSMITTED would then be dropped as old.
This seems to contradict the commit message:
"With this change, the malformed message was not delivered"
The existing fragment header mismatch path has the same weakness, and
this patch adds a second rejection path that shares it.
Could the in-progress inc be dropped here instead? That would mean
calling rds_inc_put(&ic->i_ibinc->ii_inc) and clearing ic->i_ibinc and
ic->i_recv_data_rem. Another option is to stop reassembly once the
connection is in error.
> list_add_tail(&recv->r_frag->f_item, &ibinc->ii_frags);
> recv->r_frag = NULL;
>
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261006205204.1322102-1-tjdqudcks0424%40naver.com
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-10-09 11:52 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-06 20:52 [PATCH net] RDS/IB: validate receive completion payload length sungbyeongchan
2026-10-06 20:55 ` netdev-bot+sinfo
2026-10-07 1:13 ` Allison Henderson
2026-10-09 11:52 ` netdev-bot+sashiko
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox