* [PATCH net v2 0/2] net/smc: close the SMC-D teardown window around the ghost send buffer
@ 2026-08-08 7:21 Bryam Vargas via B4 Relay
2026-08-08 7:21 ` [PATCH net v2 1/2] net/smc: unregister the connection before draining the rx tasklet Bryam Vargas via B4 Relay
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Bryam Vargas via B4 Relay @ 2026-08-08 7:21 UTC (permalink / raw)
To: Dust Li, Sidraya Jayagond, Paolo Abeni, David S. Miller,
Jakub Kicinski, Wenjia Zhang, D. Wythe, Mahanta Jambigi, Tony Lu,
Wen Gu, Eric Dumazet
Cc: linux-kernel, linux-rdma, netdev, Simon Horman, linux-s390
Both patches only matter on the SMC-D DMB-nocopy path, where the ghost send
buffer exists, and the only in-tree provider of support_mmapped_rdmb is
dibs_loopback. CONFIG_DIBS_LO is default n and its help calls it a testing aid,
so on a stock config neither bug is reachable.
v1 moved smcd_buf_detach() after the drain. Dust Li replied that it does not
fully eliminate the race and asked whether RCU is the better shape. He is right
about the first part; I built both and measured them.
An SMC-D loopback KASAN rig, one module binary, teardown form selected at
runtime. "path" counts connections reaching either teardown site with the link
group already unlinked, "armable" how many of those still had both gates in
smcd_handle_irq() open when the drain returned, "re-armed" the device arming
the tasklet again afterwards:
form path armable re-armed
upstream 169 73 29
v1 (drain, then detach) 172 78 33
unregister first, then drain 31 0 0
v1 + RCU 24 9 3
Two caveats on that table. The last two arms ran far shorter than the first two,
so compare the armable/re-armed ratios rather than the absolute path counts. And
the third row also forced tasklet_kill() in the !soft path, which 1/2 does not;
that was inert here because smc_lgr_terminate_work() passes soft=true, so the
same call ran either way.
The reorder alone leaves the window open, which is what Dust saw. RCU doesn't
close it either: smcd_buf_detach() both frees the descriptor and clears the
field, and RCU defers only the free, so a re-armed tasklet still runs and still
finds conn->sndbuf_desc NULL. The gate has to be shut before the drain, and
that is 1/2. RCU on the descriptor would still be a reasonable thing to want
for the free itself; it just doesn't substitute for 1/2, so I didn't fold it
in. Your call if you want it anyway.
Caveat on 1/2: the two changes the table covers -- unconditional
smc_ism_unset_conn(), and drain before detach -- were measured together, not
separately. It also clears conn->sndbuf_desc before freeing it, so a reader
that samples the pointer cannot get one that is already freed; that part is
by inspection.
2/2 is a second dereference the same teardown reaches, found while running the
above. smc_close_stream_wait() calls smc_tx_prepared_sends() from inside
sk_wait_event(), which evaluates its condition once with the socket lock
released, and a terminating link group clears conn->sndbuf_desc right there.
SIOCOUTQ reads the same field by hand, and smc_close_cancel_work() drops the
socket lock across two cancel_*_sync() calls, so 2/2 bounds that too. Eight
faults across three boots, the earliest 89 seconds in:
RIP: smc_close_stream_wait+0x66d [smc]
smc_close_active -> __smc_release -> smc_release -> __x64_sys_close
The faulting address is NULL plus offsetof(struct smc_buf_desc, len), nothing
there is attacker-chosen, and the value read never reaches userspace, so there
is no memory-safety primitive and no leak oracle -- it is an oops. The task dies
inside close() holding the socket lock, so I would expect the socket to leak with
it, but I didn't isolate that from the rig's own effects and I'm not claiming it.
Reaching either bug needs a link-group teardown while a socket is parked in that
wait. smc_lgr_cleanup_early() off a failed first-contact handshake gets there, as
does smc_clc_wait_msg() on a peer DECLINE with FIRST_CONTACT -- both by
inspection. The rig instead drove smc_lgr_terminate_sched() from a debug module
parameter, so only the initiation is synthetic; the unlink, the deferred worker,
smc_conn_free() and smcd_handle_irq() are the unmodified path. Logs and the rig
on request.
I haven't touched tasklet_unlock_wait() in the !soft path of smc_conn_kill().
It waits out TASKLET_STATE_RUN without clearing TASKLET_STATE_SCHED, but I have
no measurement showing that reachable here, so it stays as it is.
v2:
- 1/2: unregister the connection unconditionally rather than only while the
link group is still on its device list. That guard, not the ordering, is why
the tasklet can be re-armed after tasklet_kill().
- 2/2: new.
- v1: https://lore.kernel.org/all/20260726-b4-disp-a135b4e5-v1-1-705aaec79986@proton.me/
Bryam Vargas (2):
net/smc: unregister the connection before draining the rx tasklet
net/smc: do not dereference an unset send buffer on the SMC-D teardown path
net/smc/af_smc.c | 3 ++-
net/smc/smc_core.c | 13 +++++++------
net/smc/smc_tx.h | 6 +++++-
3 files changed, 14 insertions(+), 8 deletions(-)
base-commit: 3dbb44d88b1e
---
Bryam Vargas (2):
net/smc: unregister the connection before draining the rx tasklet
net/smc: do not dereference an unset send buffer on the SMC-D teardown path
net/smc/af_smc.c | 3 ++-
net/smc/smc_core.c | 13 +++++++------
net/smc/smc_tx.h | 6 +++++-
3 files changed, 14 insertions(+), 8 deletions(-)
---
base-commit: 3dbb44d88b1e94dd31fe43588af7437b34b44d56
change-id: 20260808-b4-disp-22f119e6-b3009a5443c1
Best regards,
--
Bryam Vargas <hexlabsecurity@proton.me>
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH net v2 1/2] net/smc: unregister the connection before draining the rx tasklet
2026-08-08 7:21 [PATCH net v2 0/2] net/smc: close the SMC-D teardown window around the ghost send buffer Bryam Vargas via B4 Relay
@ 2026-08-08 7:21 ` Bryam Vargas via B4 Relay
2026-08-13 5:47 ` Sidraya Jayagond
2026-08-13 7:29 ` Tony Lu
2026-08-08 7:21 ` [PATCH net v2 2/2] net/smc: do not dereference an unset send buffer on the SMC-D teardown path Bryam Vargas via B4 Relay
2026-08-13 0:10 ` [PATCH net v2 0/2] net/smc: close the SMC-D teardown window around the ghost send buffer Jakub Kicinski
2 siblings, 2 replies; 8+ messages in thread
From: Bryam Vargas via B4 Relay @ 2026-08-08 7:21 UTC (permalink / raw)
To: Dust Li, Sidraya Jayagond, Paolo Abeni, David S. Miller,
Jakub Kicinski, Wenjia Zhang, D. Wythe, Mahanta Jambigi, Tony Lu,
Wen Gu, Eric Dumazet
Cc: linux-kernel, linux-rdma, netdev, Simon Horman, linux-s390
From: Bryam Vargas <hexlabsecurity@proton.me>
smc_conn_free() calls smc_ism_unset_conn() only while the link group is
still on its device list, and never sets conn->killed.
smc_lgr_terminate_sched() unlinks the group immediately and defers killing
its connections to a work item, so a connection freed in that window keeps
its smcd->conn[] slot with both gates in smcd_handle_irq() open, and the
device can re-arm the receive tasklet after tasklet_kill() has returned. On
the DMB-nocopy path the ghost send buffer is freed right after that drain,
so the re-armed tasklet dereferences it.
Unregister unconditionally and drain before the detach at both teardown
sites, mirroring rmb_desc, which smc_buf_unuse() releases after the drain.
Clear conn->sndbuf_desc before freeing it as well, so a reader that samples
the pointer cannot get one that is already freed.
Fixes: ae2be35cbed2 ("net/smc: {at|de}tach sndbuf to peer DMB if supported")
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
---
net/smc/smc_core.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c
index b4208cb186c5..181647982490 100644
--- a/net/smc/smc_core.c
+++ b/net/smc/smc_core.c
@@ -1209,14 +1209,16 @@ static void smcd_buf_detach(struct smc_connection *conn)
{
struct smcd_dev *smcd = conn->lgr->smcd;
u64 peer_token = conn->peer_token;
+ struct smc_buf_desc *buf_desc;
if (!conn->sndbuf_desc)
return;
smc_ism_detach_dmb(smcd, peer_token);
- kfree(conn->sndbuf_desc);
+ buf_desc = conn->sndbuf_desc;
conn->sndbuf_desc = NULL;
+ kfree(buf_desc);
}
static void smc_buf_unuse(struct smc_connection *conn,
@@ -1268,11 +1270,10 @@ void smc_conn_free(struct smc_connection *conn)
goto lgr_put;
if (lgr->is_smcd) {
- if (!list_empty(&lgr->list))
- smc_ism_unset_conn(conn);
+ smc_ism_unset_conn(conn);
+ tasklet_kill(&conn->rx_tsklet);
if (smc_ism_support_dmb_nocopy(lgr->smcd))
smcd_buf_detach(conn);
- tasklet_kill(&conn->rx_tsklet);
} else {
smc_cdc_wait_pend_tx_wr(conn);
if (current_work() != &conn->abort_work)
@@ -1525,12 +1526,12 @@ static void smc_conn_kill(struct smc_connection *conn, bool soft)
smc_sk_wake_ups(smc);
if (conn->lgr->is_smcd) {
smc_ism_unset_conn(conn);
- if (smc_ism_support_dmb_nocopy(conn->lgr->smcd))
- smcd_buf_detach(conn);
if (soft)
tasklet_kill(&conn->rx_tsklet);
else
tasklet_unlock_wait(&conn->rx_tsklet);
+ if (smc_ism_support_dmb_nocopy(conn->lgr->smcd))
+ smcd_buf_detach(conn);
} else {
smc_cdc_wait_pend_tx_wr(conn);
}
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH net v2 1/2] net/smc: unregister the connection before draining the rx tasklet
2026-08-08 7:21 ` [PATCH net v2 1/2] net/smc: unregister the connection before draining the rx tasklet Bryam Vargas via B4 Relay
@ 2026-08-13 5:47 ` Sidraya Jayagond
2026-08-13 7:29 ` Tony Lu
1 sibling, 0 replies; 8+ messages in thread
From: Sidraya Jayagond @ 2026-08-13 5:47 UTC (permalink / raw)
To: hexlabsecurity, Dust Li, Paolo Abeni, David S. Miller,
Jakub Kicinski, Wenjia Zhang, D. Wythe, Mahanta Jambigi, Tony Lu,
Wen Gu, Eric Dumazet
Cc: linux-kernel, linux-rdma, netdev, Simon Horman, linux-s390
On 08/08/26 12:51 pm, Bryam Vargas via B4 Relay wrote:
> From: Bryam Vargas <hexlabsecurity@proton.me>
>
> smc_conn_free() calls smc_ism_unset_conn() only while the link group is
> still on its device list, and never sets conn->killed.
> smc_lgr_terminate_sched() unlinks the group immediately and defers killing
> its connections to a work item, so a connection freed in that window keeps
> its smcd->conn[] slot with both gates in smcd_handle_irq() open, and the
> device can re-arm the receive tasklet after tasklet_kill() has returned. On
> the DMB-nocopy path the ghost send buffer is freed right after that drain,
> so the re-armed tasklet dereferences it.
>
> Unregister unconditionally and drain before the detach at both teardown
> sites, mirroring rmb_desc, which smc_buf_unuse() releases after the drain.
> Clear conn->sndbuf_desc before freeing it as well, so a reader that samples
> the pointer cannot get one that is already freed.
>
> Fixes: ae2be35cbed2 ("net/smc: {at|de}tach sndbuf to peer DMB if supported")
> Cc: stable@vger.kernel.org
> Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
> ---
> net/smc/smc_core.c | 13 +++++++------
> 1 file changed, 7 insertions(+), 6 deletions(-)
>
> diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c
> index b4208cb186c5..181647982490 100644
> --- a/net/smc/smc_core.c
> +++ b/net/smc/smc_core.c
> @@ -1209,14 +1209,16 @@ static void smcd_buf_detach(struct smc_connection *conn)
> {
> struct smcd_dev *smcd = conn->lgr->smcd;
> u64 peer_token = conn->peer_token;
> + struct smc_buf_desc *buf_desc;
>
> if (!conn->sndbuf_desc)
> return;
>
> smc_ism_detach_dmb(smcd, peer_token);
>
> - kfree(conn->sndbuf_desc);
> + buf_desc = conn->sndbuf_desc;
> conn->sndbuf_desc = NULL;
> + kfree(buf_desc);
> }
>
> static void smc_buf_unuse(struct smc_connection *conn,
> @@ -1268,11 +1270,10 @@ void smc_conn_free(struct smc_connection *conn)
> goto lgr_put;
>
> if (lgr->is_smcd) {
> - if (!list_empty(&lgr->list))
> - smc_ism_unset_conn(conn);
> + smc_ism_unset_conn(conn);
> + tasklet_kill(&conn->rx_tsklet);
> if (smc_ism_support_dmb_nocopy(lgr->smcd))
> smcd_buf_detach(conn);
> - tasklet_kill(&conn->rx_tsklet);
> } else {
> smc_cdc_wait_pend_tx_wr(conn);
> if (current_work() != &conn->abort_work)
> @@ -1525,12 +1526,12 @@ static void smc_conn_kill(struct smc_connection *conn, bool soft)
> smc_sk_wake_ups(smc);
> if (conn->lgr->is_smcd) {
> smc_ism_unset_conn(conn);
> - if (smc_ism_support_dmb_nocopy(conn->lgr->smcd))
> - smcd_buf_detach(conn);
> if (soft)
> tasklet_kill(&conn->rx_tsklet);
> else
> tasklet_unlock_wait(&conn->rx_tsklet);
> + if (smc_ism_support_dmb_nocopy(conn->lgr->smcd))
> + smcd_buf_detach(conn);
> } else {
> smc_cdc_wait_pend_tx_wr(conn);
> }
>
Looks good to me.
Reviewed-by: Sidraya Jayagond <sidraya@linux.ibm.com>
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH net v2 1/2] net/smc: unregister the connection before draining the rx tasklet
2026-08-08 7:21 ` [PATCH net v2 1/2] net/smc: unregister the connection before draining the rx tasklet Bryam Vargas via B4 Relay
2026-08-13 5:47 ` Sidraya Jayagond
@ 2026-08-13 7:29 ` Tony Lu
1 sibling, 0 replies; 8+ messages in thread
From: Tony Lu @ 2026-08-13 7:29 UTC (permalink / raw)
To: hexlabsecurity
Cc: Dust Li, Sidraya Jayagond, Paolo Abeni, David S. Miller,
Jakub Kicinski, Wenjia Zhang, D. Wythe, Mahanta Jambigi, Wen Gu,
Eric Dumazet, linux-kernel, linux-rdma, netdev, Simon Horman,
linux-s390
On Sat, Aug 08, 2026 at 02:21:23AM -0500, Bryam Vargas via B4 Relay wrote:
> From: Bryam Vargas <hexlabsecurity@proton.me>
>
> smc_conn_free() calls smc_ism_unset_conn() only while the link group is
> still on its device list, and never sets conn->killed.
> smc_lgr_terminate_sched() unlinks the group immediately and defers killing
> its connections to a work item, so a connection freed in that window keeps
> its smcd->conn[] slot with both gates in smcd_handle_irq() open, and the
> device can re-arm the receive tasklet after tasklet_kill() has returned. On
> the DMB-nocopy path the ghost send buffer is freed right after that drain,
> so the re-armed tasklet dereferences it.
>
> Unregister unconditionally and drain before the detach at both teardown
> sites, mirroring rmb_desc, which smc_buf_unuse() releases after the drain.
> Clear conn->sndbuf_desc before freeing it as well, so a reader that samples
> the pointer cannot get one that is already freed.
>
> Fixes: ae2be35cbed2 ("net/smc: {at|de}tach sndbuf to peer DMB if supported")
> Cc: stable@vger.kernel.org
> Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
Reviewed-by: Tony Lu <tonylu@linux.alibaba.com>
> ---
> net/smc/smc_core.c | 13 +++++++------
> 1 file changed, 7 insertions(+), 6 deletions(-)
>
> diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c
> index b4208cb186c5..181647982490 100644
> --- a/net/smc/smc_core.c
> +++ b/net/smc/smc_core.c
> @@ -1209,14 +1209,16 @@ static void smcd_buf_detach(struct smc_connection *conn)
> {
> struct smcd_dev *smcd = conn->lgr->smcd;
> u64 peer_token = conn->peer_token;
> + struct smc_buf_desc *buf_desc;
>
> if (!conn->sndbuf_desc)
> return;
>
> smc_ism_detach_dmb(smcd, peer_token);
>
> - kfree(conn->sndbuf_desc);
> + buf_desc = conn->sndbuf_desc;
> conn->sndbuf_desc = NULL;
> + kfree(buf_desc);
> }
>
> static void smc_buf_unuse(struct smc_connection *conn,
> @@ -1268,11 +1270,10 @@ void smc_conn_free(struct smc_connection *conn)
> goto lgr_put;
>
> if (lgr->is_smcd) {
> - if (!list_empty(&lgr->list))
> - smc_ism_unset_conn(conn);
> + smc_ism_unset_conn(conn);
> + tasklet_kill(&conn->rx_tsklet);
> if (smc_ism_support_dmb_nocopy(lgr->smcd))
> smcd_buf_detach(conn);
> - tasklet_kill(&conn->rx_tsklet);
> } else {
> smc_cdc_wait_pend_tx_wr(conn);
> if (current_work() != &conn->abort_work)
> @@ -1525,12 +1526,12 @@ static void smc_conn_kill(struct smc_connection *conn, bool soft)
> smc_sk_wake_ups(smc);
> if (conn->lgr->is_smcd) {
> smc_ism_unset_conn(conn);
> - if (smc_ism_support_dmb_nocopy(conn->lgr->smcd))
> - smcd_buf_detach(conn);
> if (soft)
> tasklet_kill(&conn->rx_tsklet);
> else
> tasklet_unlock_wait(&conn->rx_tsklet);
> + if (smc_ism_support_dmb_nocopy(conn->lgr->smcd))
> + smcd_buf_detach(conn);
> } else {
> smc_cdc_wait_pend_tx_wr(conn);
> }
>
> --
> 2.55.0
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH net v2 2/2] net/smc: do not dereference an unset send buffer on the SMC-D teardown path
2026-08-08 7:21 [PATCH net v2 0/2] net/smc: close the SMC-D teardown window around the ghost send buffer Bryam Vargas via B4 Relay
2026-08-08 7:21 ` [PATCH net v2 1/2] net/smc: unregister the connection before draining the rx tasklet Bryam Vargas via B4 Relay
@ 2026-08-08 7:21 ` Bryam Vargas via B4 Relay
2026-08-13 5:47 ` Sidraya Jayagond
2026-08-13 7:29 ` Tony Lu
2026-08-13 0:10 ` [PATCH net v2 0/2] net/smc: close the SMC-D teardown window around the ghost send buffer Jakub Kicinski
2 siblings, 2 replies; 8+ messages in thread
From: Bryam Vargas via B4 Relay @ 2026-08-08 7:21 UTC (permalink / raw)
To: Dust Li, Sidraya Jayagond, Paolo Abeni, David S. Miller,
Jakub Kicinski, Wenjia Zhang, D. Wythe, Mahanta Jambigi, Tony Lu,
Wen Gu, Eric Dumazet
Cc: linux-kernel, linux-rdma, netdev, Simon Horman, linux-s390
From: Bryam Vargas <hexlabsecurity@proton.me>
smc_close_stream_wait() calls smc_tx_prepared_sends() from inside its
sk_wait_event() condition, and sk_wait_event() evaluates that condition
once with the socket lock released. smcd_buf_detach() clears
conn->sndbuf_desc from smc_conn_kill() under lock_sock(), so a link group
terminating while a socket waits there leaves the helper dereferencing
NULL, faulting out of close(). SIOCOUTQ reads the field by hand, and
smc_close_cancel_work() drops the lock across two cancel_*_sync() calls.
Sample the pointer once in the helper, report nothing prepared while it is
unset, and bound the ioctl the same way. The receive tasklet dereferences
the field directly in smc_cdc_msg_recv_action(), not through this helper;
1/2 is what keeps it from running that late.
Fixes: ae2be35cbed2 ("net/smc: {at|de}tach sndbuf to peer DMB if supported")
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
---
net/smc/af_smc.c | 3 ++-
net/smc/smc_tx.h | 6 +++++-
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index 00403175b740..cff910cedbfc 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -3233,7 +3233,8 @@ int smc_ioctl(struct socket *sock, unsigned int cmd,
return -EINVAL;
}
if (smc->sk.sk_state == SMC_INIT ||
- smc->sk.sk_state == SMC_CLOSED)
+ smc->sk.sk_state == SMC_CLOSED ||
+ !READ_ONCE(smc->conn.sndbuf_desc))
answ = 0;
else
answ = smc->conn.sndbuf_desc->len -
diff --git a/net/smc/smc_tx.h b/net/smc/smc_tx.h
index a59f370b8b43..610a945aefd6 100644
--- a/net/smc/smc_tx.h
+++ b/net/smc/smc_tx.h
@@ -20,11 +20,15 @@
static inline int smc_tx_prepared_sends(struct smc_connection *conn)
{
+ struct smc_buf_desc *sndbuf_desc = READ_ONCE(conn->sndbuf_desc);
union smc_host_cursor sent, prep;
+ if (!sndbuf_desc)
+ return 0;
+
smc_curs_copy(&sent, &conn->tx_curs_sent, conn);
smc_curs_copy(&prep, &conn->tx_curs_prep, conn);
- return smc_curs_diff(conn->sndbuf_desc->len, &sent, &prep);
+ return smc_curs_diff(sndbuf_desc->len, &sent, &prep);
}
void smc_tx_pending(struct smc_connection *conn);
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH net v2 2/2] net/smc: do not dereference an unset send buffer on the SMC-D teardown path
2026-08-08 7:21 ` [PATCH net v2 2/2] net/smc: do not dereference an unset send buffer on the SMC-D teardown path Bryam Vargas via B4 Relay
@ 2026-08-13 5:47 ` Sidraya Jayagond
2026-08-13 7:29 ` Tony Lu
1 sibling, 0 replies; 8+ messages in thread
From: Sidraya Jayagond @ 2026-08-13 5:47 UTC (permalink / raw)
To: hexlabsecurity, Dust Li, Paolo Abeni, David S. Miller,
Jakub Kicinski, Wenjia Zhang, D. Wythe, Mahanta Jambigi, Tony Lu,
Wen Gu, Eric Dumazet
Cc: linux-kernel, linux-rdma, netdev, Simon Horman, linux-s390
On 08/08/26 12:51 pm, Bryam Vargas via B4 Relay wrote:
> From: Bryam Vargas <hexlabsecurity@proton.me>
>
> smc_close_stream_wait() calls smc_tx_prepared_sends() from inside its
> sk_wait_event() condition, and sk_wait_event() evaluates that condition
> once with the socket lock released. smcd_buf_detach() clears
> conn->sndbuf_desc from smc_conn_kill() under lock_sock(), so a link group
> terminating while a socket waits there leaves the helper dereferencing
> NULL, faulting out of close(). SIOCOUTQ reads the field by hand, and
> smc_close_cancel_work() drops the lock across two cancel_*_sync() calls.
>
> Sample the pointer once in the helper, report nothing prepared while it is
> unset, and bound the ioctl the same way. The receive tasklet dereferences
> the field directly in smc_cdc_msg_recv_action(), not through this helper;
> 1/2 is what keeps it from running that late.
>
> Fixes: ae2be35cbed2 ("net/smc: {at|de}tach sndbuf to peer DMB if supported")
> Cc: stable@vger.kernel.org
> Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
> ---
> net/smc/af_smc.c | 3 ++-
> net/smc/smc_tx.h | 6 +++++-
> 2 files changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
> index 00403175b740..cff910cedbfc 100644
> --- a/net/smc/af_smc.c
> +++ b/net/smc/af_smc.c
> @@ -3233,7 +3233,8 @@ int smc_ioctl(struct socket *sock, unsigned int cmd,
> return -EINVAL;
> }
> if (smc->sk.sk_state == SMC_INIT ||
> - smc->sk.sk_state == SMC_CLOSED)
> + smc->sk.sk_state == SMC_CLOSED ||
> + !READ_ONCE(smc->conn.sndbuf_desc))
> answ = 0;
> else
> answ = smc->conn.sndbuf_desc->len -
> diff --git a/net/smc/smc_tx.h b/net/smc/smc_tx.h
> index a59f370b8b43..610a945aefd6 100644
> --- a/net/smc/smc_tx.h
> +++ b/net/smc/smc_tx.h
> @@ -20,11 +20,15 @@
>
> static inline int smc_tx_prepared_sends(struct smc_connection *conn)
> {
> + struct smc_buf_desc *sndbuf_desc = READ_ONCE(conn->sndbuf_desc);
> union smc_host_cursor sent, prep;
>
> + if (!sndbuf_desc)
> + return 0;
> +
> smc_curs_copy(&sent, &conn->tx_curs_sent, conn);
> smc_curs_copy(&prep, &conn->tx_curs_prep, conn);
> - return smc_curs_diff(conn->sndbuf_desc->len, &sent, &prep);
> + return smc_curs_diff(sndbuf_desc->len, &sent, &prep);
> }
>
> void smc_tx_pending(struct smc_connection *conn);
>
Reviewed-by: Sidraya Jayagond <sidraya@linux.ibm.com>
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH net v2 2/2] net/smc: do not dereference an unset send buffer on the SMC-D teardown path
2026-08-08 7:21 ` [PATCH net v2 2/2] net/smc: do not dereference an unset send buffer on the SMC-D teardown path Bryam Vargas via B4 Relay
2026-08-13 5:47 ` Sidraya Jayagond
@ 2026-08-13 7:29 ` Tony Lu
1 sibling, 0 replies; 8+ messages in thread
From: Tony Lu @ 2026-08-13 7:29 UTC (permalink / raw)
To: hexlabsecurity
Cc: Dust Li, Sidraya Jayagond, Paolo Abeni, David S. Miller,
Jakub Kicinski, Wenjia Zhang, D. Wythe, Mahanta Jambigi, Wen Gu,
Eric Dumazet, linux-kernel, linux-rdma, netdev, Simon Horman,
linux-s390
On Sat, Aug 08, 2026 at 02:21:24AM -0500, Bryam Vargas via B4 Relay wrote:
> From: Bryam Vargas <hexlabsecurity@proton.me>
>
> smc_close_stream_wait() calls smc_tx_prepared_sends() from inside its
> sk_wait_event() condition, and sk_wait_event() evaluates that condition
> once with the socket lock released. smcd_buf_detach() clears
> conn->sndbuf_desc from smc_conn_kill() under lock_sock(), so a link group
> terminating while a socket waits there leaves the helper dereferencing
> NULL, faulting out of close(). SIOCOUTQ reads the field by hand, and
> smc_close_cancel_work() drops the lock across two cancel_*_sync() calls.
>
> Sample the pointer once in the helper, report nothing prepared while it is
> unset, and bound the ioctl the same way. The receive tasklet dereferences
> the field directly in smc_cdc_msg_recv_action(), not through this helper;
> 1/2 is what keeps it from running that late.
>
> Fixes: ae2be35cbed2 ("net/smc: {at|de}tach sndbuf to peer DMB if supported")
> Cc: stable@vger.kernel.org
> Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
Reviewed-by: Tony Lu <tonylu@linux.alibaba.com>
> ---
> net/smc/af_smc.c | 3 ++-
> net/smc/smc_tx.h | 6 +++++-
> 2 files changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
> index 00403175b740..cff910cedbfc 100644
> --- a/net/smc/af_smc.c
> +++ b/net/smc/af_smc.c
> @@ -3233,7 +3233,8 @@ int smc_ioctl(struct socket *sock, unsigned int cmd,
> return -EINVAL;
> }
> if (smc->sk.sk_state == SMC_INIT ||
> - smc->sk.sk_state == SMC_CLOSED)
> + smc->sk.sk_state == SMC_CLOSED ||
> + !READ_ONCE(smc->conn.sndbuf_desc))
> answ = 0;
> else
> answ = smc->conn.sndbuf_desc->len -
> diff --git a/net/smc/smc_tx.h b/net/smc/smc_tx.h
> index a59f370b8b43..610a945aefd6 100644
> --- a/net/smc/smc_tx.h
> +++ b/net/smc/smc_tx.h
> @@ -20,11 +20,15 @@
>
> static inline int smc_tx_prepared_sends(struct smc_connection *conn)
> {
> + struct smc_buf_desc *sndbuf_desc = READ_ONCE(conn->sndbuf_desc);
> union smc_host_cursor sent, prep;
>
> + if (!sndbuf_desc)
> + return 0;
> +
> smc_curs_copy(&sent, &conn->tx_curs_sent, conn);
> smc_curs_copy(&prep, &conn->tx_curs_prep, conn);
> - return smc_curs_diff(conn->sndbuf_desc->len, &sent, &prep);
> + return smc_curs_diff(sndbuf_desc->len, &sent, &prep);
> }
>
> void smc_tx_pending(struct smc_connection *conn);
>
> --
> 2.55.0
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net v2 0/2] net/smc: close the SMC-D teardown window around the ghost send buffer
2026-08-08 7:21 [PATCH net v2 0/2] net/smc: close the SMC-D teardown window around the ghost send buffer Bryam Vargas via B4 Relay
2026-08-08 7:21 ` [PATCH net v2 1/2] net/smc: unregister the connection before draining the rx tasklet Bryam Vargas via B4 Relay
2026-08-08 7:21 ` [PATCH net v2 2/2] net/smc: do not dereference an unset send buffer on the SMC-D teardown path Bryam Vargas via B4 Relay
@ 2026-08-13 0:10 ` Jakub Kicinski
2 siblings, 0 replies; 8+ messages in thread
From: Jakub Kicinski @ 2026-08-13 0:10 UTC (permalink / raw)
To: Bryam Vargas via B4 Relay, Dust Li, Sidraya Jayagond,
Wenjia Zhang, D. Wythe, Mahanta Jambigi, Tony Lu, Wen Gu
Cc: hexlabsecurity, Paolo Abeni, David S. Miller, Eric Dumazet,
linux-kernel, linux-rdma, netdev, Simon Horman, linux-s390
On Sat, 08 Aug 2026 02:21:22 -0500 Bryam Vargas via B4 Relay wrote:
> Both patches only matter on the SMC-D DMB-nocopy path, where the ghost send
> buffer exists, and the only in-tree provider of support_mmapped_rdmb is
> dibs_loopback. CONFIG_DIBS_LO is default n and its help calls it a testing aid,
> so on a stock config neither bug is reachable.
SMC maintainers, please TAL.
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-08-13 7:29 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-08 7:21 [PATCH net v2 0/2] net/smc: close the SMC-D teardown window around the ghost send buffer Bryam Vargas via B4 Relay
2026-08-08 7:21 ` [PATCH net v2 1/2] net/smc: unregister the connection before draining the rx tasklet Bryam Vargas via B4 Relay
2026-08-13 5:47 ` Sidraya Jayagond
2026-08-13 7:29 ` Tony Lu
2026-08-08 7:21 ` [PATCH net v2 2/2] net/smc: do not dereference an unset send buffer on the SMC-D teardown path Bryam Vargas via B4 Relay
2026-08-13 5:47 ` Sidraya Jayagond
2026-08-13 7:29 ` Tony Lu
2026-08-13 0:10 ` [PATCH net v2 0/2] net/smc: close the SMC-D teardown window around the ghost send buffer Jakub Kicinski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox