From: Sidraya Jayagond <sidraya@linux.ibm.com>
To: Nguyen Le Thanh Tung <nguyenlethanhtung555@gmail.com>,
"D . Wythe" <alibuda@linux.alibaba.com>,
Dust Li <dust.li@linux.alibaba.com>,
Wenjia Zhang <wenjia@linux.ibm.com>
Cc: Mahanta Jambigi <mjambigi@linux.ibm.com>,
Tony Lu <tonylu@linux.alibaba.com>,
Wen Gu <guwen@linux.alibaba.com>,
netdev@vger.kernel.org, linux-rdma@vger.kernel.org,
linux-s390@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH net] net/smc: clamp peer supplied CDC cursors to the buffer size
Date: Mon, 27 Jul 2026 13:15:03 +0530 [thread overview]
Message-ID: <af7fc73c-b932-4234-ac2f-91e96669048b@linux.ibm.com> (raw)
In-Reply-To: <20260727040806.1911118-1-nguyenlethanhtung555@gmail.com>
Hi Nguyen,
I think Bryam already sent a similar patch to the mailing-list.
https://lore.kernel.org/netdev/20260723-b4-disp-0d07164f-v5-1-6a9e235dbc4e@proton.me/
On 27/07/26 9:38 am, Nguyen Le Thanh Tung wrote:
> smc_cdc_cursor_to_host() converts a peer supplied CDC cursor into the
> connection's host cursor. The count field is taken verbatim off the
> wire and is only compared against the previously known cursor to
> enforce monotonicity - it is never validated against the size of the
> buffer it indexes:
>
> temp.count = ntohl(net.count);
> temp.wrap = ntohs(net.wrap);
> if ((old.wrap > temp.wrap) && temp.wrap)
> return;
> if ((old.wrap == temp.wrap) && (old.count > temp.count))
> return;
> smc_curs_copy(local, &temp, conn);
>
> On the first CDC message of a connection old is {wrap = 0, count = 0},
> so both guards are false for any peer chosen pair and a count of up to
> 0xffffffff is accepted unconditionally. A conforming peer never emits
> count >= size: smc_curs_add() wraps at the buffer size, which is what
> every consumer of the cursor assumes.
>
> The most direct consequence is in smc_cdc_handle_urg_data_arrival(),
> which uses the producer cursor as a raw index with no further check:
>
> base = (char *)conn->rmb_desc->cpu_addr + conn->rx_off;
> if (conn->urg_curs.count)
> conn->urg_rx_byte = *(base + conn->urg_curs.count - 1);
>
> That path is reached from the receive path whenever the producer cursor
> advances and prod_flags.urg_data_present is set - a single bit copied
> verbatim from the wire - so a peer can read at an attacker chosen offset
> of up to 4GB from a known heap pointer, far outside the RMB. The same
> unvalidated cursor also feeds the atomic_add() into conn->bytes_to_rcv,
> breaking the 0 <= bytes_to_rcv <= rmb_desc->len invariant that
> smc_rx_recvmsg() relies on when it computes its second copy chunk.
>
> Clamp count to the size of the buffer the cursor refers to, so that
> everything derived from it stays inside that buffer. The producer
> cursor indexes the local RMB and is bounded by conn->rmb_desc->len, the
> consumer cursor refers to the peer's RMBE and is bounded by
> conn->peer_rmbe_size - the same sizes smc_cdc_msg_recv_action() already
> passes to smc_curs_diff() for these two cursors, and which it already
> dereferences unconditionally a few lines after the conversion, so no new
> pointer is assumed valid here. The SMC-D path reads the cursors from
> the DMB rather than off the wire, but they are equally peer controlled
> and reach the same consumers, so clamp there as well. For SMC-D the DMB
> is registered with sizeof(struct smcd_cdc_msg) extra bytes and
> buf_desc->len holds the remainder (smcd_new_buf_create()), so bounding
> count by rmb_desc->len also keeps the rx_off based dereference inside
> the allocation.
>
> Found by code inspection. The unbounded acceptance was confirmed by
> calling the unmodified smc_cdc_cursor_to_host() from a module with
> old = {0, 0} and a peer cursor of count = 0x40000000: the value is
> copied through unchanged. Replaying the resulting dereference against a
> real 64 byte kmalloc() allocation produces a clean KASAN
> slab-out-of-bounds read.
>
> Fixes: 5f08318f617b ("smc: connection data control (CDC)")
> Signed-off-by: Nguyen Le Thanh Tung <nguyenlethanhtung555@gmail.com>
> ---
> Compile tested on 6.8.12 with CONFIG_SMC=m: `make W=1 net/smc/` produces
> no new warnings. The two functions this patch touches are byte identical
> in 6.8 and current mainline.
>
> net/smc/smc_cdc.h | 34 ++++++++++++++++++++++++++++------
> 1 file changed, 28 insertions(+), 6 deletions(-)
>
> diff --git a/net/smc/smc_cdc.h b/net/smc/smc_cdc.h
> index 696cc11..a71e46d 100644
> --- a/net/smc/smc_cdc.h
> +++ b/net/smc/smc_cdc.h
> @@ -219,16 +219,34 @@ static inline void smc_host_msg_to_cdc(struct smc_cdc_msg *peer,
> peer->conn_state_flags = local->conn_state_flags;
> }
>
> +/* Bound a peer supplied cursor count to the size of the buffer it indexes.
> + * A conforming peer never sends count >= size (see smc_curs_add()), and every
> + * user of the cursor - the byte accounting in smc_cdc_msg_recv_action() and
> + * the direct RMB dereference in smc_cdc_handle_urg_data_arrival() - relies on
> + * that. Nothing validates it, so do it here, once, where the value enters the
> + * connection state.
> + */
> +static inline u32 smc_cdc_clamp_count(u32 count, unsigned int size)
> +{
> + if (WARN_ON_ONCE(size && count >= size))
> + count = size - 1;
> + return count;
> +}
> +
> +/* @size: size of the buffer the cursor indexes, i.e. conn->rmb_desc->len for
> + * a producer cursor and conn->peer_rmbe_size for a consumer cursor
> + */
> static inline void smc_cdc_cursor_to_host(union smc_host_cursor *local,
> union smc_cdc_cursor *peer,
> - struct smc_connection *conn)
> + struct smc_connection *conn,
> + unsigned int size)
> {
> union smc_host_cursor temp, old;
> union smc_cdc_cursor net;
>
> smc_curs_copy(&old, local, conn);
> smc_curs_copy_net(&net, peer, conn);
> - temp.count = ntohl(net.count);
> + temp.count = smc_cdc_clamp_count(ntohl(net.count), size);
> temp.wrap = ntohs(net.wrap);
> if ((old.wrap > temp.wrap) && temp.wrap)
> return;
> @@ -246,8 +264,10 @@ static inline void smcr_cdc_msg_to_host(struct smc_host_cdc_msg *local,
> local->len = peer->len;
> local->seqno = ntohs(peer->seqno);
> local->token = ntohl(peer->token);
> - smc_cdc_cursor_to_host(&local->prod, &peer->prod, conn);
> - smc_cdc_cursor_to_host(&local->cons, &peer->cons, conn);
> + smc_cdc_cursor_to_host(&local->prod, &peer->prod, conn,
> + conn->rmb_desc->len);
> + smc_cdc_cursor_to_host(&local->cons, &peer->cons, conn,
> + conn->peer_rmbe_size);
> local->prod_flags = peer->prod_flags;
> local->conn_state_flags = peer->conn_state_flags;
> }
> @@ -259,11 +279,13 @@ static inline void smcd_cdc_msg_to_host(struct smc_host_cdc_msg *local,
> union smc_host_cursor temp;
>
> temp.wrap = peer->prod.wrap;
> - temp.count = peer->prod.count;
> + temp.count = smc_cdc_clamp_count(peer->prod.count,
> + conn->rmb_desc->len);
> smc_curs_copy(&local->prod, &temp, conn);
>
> temp.wrap = peer->cons.wrap;
> - temp.count = peer->cons.count;
> + temp.count = smc_cdc_clamp_count(peer->cons.count,
> + conn->peer_rmbe_size);
> smc_curs_copy(&local->cons, &temp, conn);
> local->prod_flags = peer->cons.prod_flags;
> local->conn_state_flags = peer->cons.conn_state_flags;
prev parent reply other threads:[~2026-07-27 7:45 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-27 4:08 [PATCH net] net/smc: clamp peer supplied CDC cursors to the buffer size Nguyen Le Thanh Tung
2026-07-27 7:45 ` Sidraya Jayagond [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=af7fc73c-b932-4234-ac2f-91e96669048b@linux.ibm.com \
--to=sidraya@linux.ibm.com \
--cc=alibuda@linux.alibaba.com \
--cc=dust.li@linux.alibaba.com \
--cc=guwen@linux.alibaba.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rdma@vger.kernel.org \
--cc=linux-s390@vger.kernel.org \
--cc=mjambigi@linux.ibm.com \
--cc=netdev@vger.kernel.org \
--cc=nguyenlethanhtung555@gmail.com \
--cc=tonylu@linux.alibaba.com \
--cc=wenjia@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox