[PATCH net v5 2/2] net/smc: skip the DMB nocopy accounting until the send buffer is set

From: Bryam Vargas via B4 Relay

Date: Thu Oct 15 2026 - 07:53:51 EST


From: Bryam Vargas <hexlabsecurity@xxxxxxxxx>

With SMC-D DMB nocopy (the loopback device), smcd_buf_attach() sets
conn->sndbuf_desc after the connection can already receive a CDC. When
a DMB is reused, the peer of its previous connection can still hold
the DMB token, and its next consumer update makes
smc_cdc_msg_recv_action() dereference the NULL sndbuf_desc in the
nocopy accounting.

Set sndbuf_desc with a release store after sndbuf_space, and skip the
nocopy accounting while sndbuf_desc is unset. Before the attach the
current peer has consumed nothing of ours, so no update from it is
lost. The rest of the receive path handles an unset sndbuf_desc since
commit b395dd319cea ("net/smc: do not dereference an unset send buffer
on the SMC-D teardown path").

Fixes: cc0ab806fc52 ("net/smc: adapt cursor update when sndbuf and peer DMB are merged")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Bryam Vargas <hexlabsecurity@xxxxxxxxx>
---
net/smc/smc_cdc.c | 10 +++++++++-
net/smc/smc_core.c | 7 ++++---
2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/net/smc/smc_cdc.c b/net/smc/smc_cdc.c
index 7bf902ebd7ab..d6825f48f568 100644
--- a/net/smc/smc_cdc.c
+++ b/net/smc/smc_cdc.c
@@ -333,6 +333,7 @@ static void smc_cdc_msg_recv_action(struct smc_sock *smc,
union smc_host_cursor cons_old, prod_old;
struct smc_connection *conn = &smc->conn;
int diff_cons, diff_prod, diff_tx;
+ struct smc_buf_desc *sndbuf_desc;

smc_curs_copy(&prod_old, &conn->local_rx_ctrl.prod, conn);
smc_curs_copy(&cons_old, &conn->local_rx_ctrl.cons, conn);
@@ -353,12 +354,19 @@ static void smc_cdc_msg_recv_action(struct smc_sock *smc,
* peer RMB, then update tx_curs_fin and sndbuf_space
* here since peer has already consumed the data.
*/
+ sndbuf_desc = NULL;
if (conn->lgr->is_smcd &&
smc_ism_support_dmb_nocopy(conn->lgr->smcd)) {
+ /* NULL until smcd_buf_attach(), but the old peer of
+ * a reused DMB can already signal us.
+ */
+ sndbuf_desc = smp_load_acquire(&conn->sndbuf_desc);
+ }
+ if (sndbuf_desc) {
/* Calculate consumed data and
* increment free send buffer space.
*/
- diff_tx = smc_curs_diff(conn->sndbuf_desc->len,
+ diff_tx = smc_curs_diff(sndbuf_desc->len,
&conn->tx_curs_fin,
&conn->local_rx_ctrl.cons);
/* increase local sndbuf space and fin_curs */
diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c
index 26f19a00c159..9322c27145df 100644
--- a/net/smc/smc_core.c
+++ b/net/smc/smc_core.c
@@ -2603,9 +2603,10 @@ int smcd_buf_attach(struct smc_sock *smc)
buf_desc->cpu_addr =
(u8 *)buf_desc->cpu_addr + sizeof(struct smcd_cdc_msg);
buf_desc->len -= sizeof(struct smcd_cdc_msg);
- conn->sndbuf_desc = buf_desc;
- conn->sndbuf_desc->used = 1;
- atomic_set(&conn->sndbuf_space, conn->sndbuf_desc->len);
+ buf_desc->used = 1;
+ atomic_set(&conn->sndbuf_space, buf_desc->len);
+ /* Set last; pairs with the acquire in smc_cdc_msg_recv_action() */
+ smp_store_release(&conn->sndbuf_desc, buf_desc);
return 0;

free:

--
2.56.0