[PATCH net 2/2] net/smc: do not reuse the DMB of a nocopy device

From: Bryam Vargas via B4 Relay

Date: Fri Nov 13 2026 - 09:33:58 EST


From: Bryam Vargas <hexlabsecurity@xxxxxxxxx>

With DMB nocopy (the dibs loopback device) the peer writes into the RMB
through its own attachment, and it can attach late. smc_buf_unuse() puts
the DMB back in the link group's pool with its token still registered
while the old peer can still write to it: the next connection that takes
it gets the old peer's CDCs, and a peer that attaches after the other
end gave up lands in another connection's DMB.

Unregister a nocopy DMB when the connection ends instead of pooling it.
The next connection gets a new DMB and token, a peer still attached
keeps the old DMB to itself until it detaches, and a later attach fails.
Clear conn->rmb_desc, which a connect() retried on the same socket would
otherwise use after the free. Devices without nocopy keep their pool.

Fixes: ae2be35cbed2 ("net/smc: {at|de}tach sndbuf to peer DMB if supported")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Bryam Vargas <hexlabsecurity@xxxxxxxxx>
---
net/smc/smc_core.c | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)

diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c
index a3164201c142..88855d9f6617 100644
--- a/net/smc/smc_core.c
+++ b/net/smc/smc_core.c
@@ -1243,6 +1243,22 @@ static void smcd_buf_detach(struct smc_connection *conn)
kfree(buf_desc);
}

+/* With DMB nocopy the peer writes into the RMB through its own
+ * attachment, which can outlive this connection: unregister the DMB
+ * instead of pooling it, so the next connection gets a new one.
+ */
+static void smcd_rmb_drop(struct smc_connection *conn,
+ struct smc_link_group *lgr)
+{
+ struct smc_buf_desc *rmb_desc = conn->rmb_desc;
+
+ down_write(&lgr->rmbs_lock);
+ smc_lgr_buf_list_del(lgr, true, rmb_desc);
+ up_write(&lgr->rmbs_lock);
+ WRITE_ONCE(conn->rmb_desc, NULL);
+ smc_buf_free(lgr, true, rmb_desc);
+}
+
static void smc_buf_unuse(struct smc_connection *conn,
struct smc_link_group *lgr)
{
@@ -1266,8 +1282,13 @@ static void smc_buf_unuse(struct smc_connection *conn,
smcr_buf_unuse(conn->rmb_desc, true, lgr);
} else {
bufsize += sizeof(struct smcd_cdc_msg);
- memzero_explicit(conn->rmb_desc->cpu_addr, bufsize);
- WRITE_ONCE(conn->rmb_desc->used, 0);
+ if (smc_ism_support_dmb_nocopy(lgr->smcd)) {
+ smcd_rmb_drop(conn, lgr);
+ } else {
+ memzero_explicit(conn->rmb_desc->cpu_addr,
+ bufsize);
+ WRITE_ONCE(conn->rmb_desc->used, 0);
+ }
}
SMC_STAT_RMB_SIZE(smc, is_smcd, true, false, bufsize);
}

--
2.56.0