mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 14:33:24 -04:00
net/smc: do not dereference an unset send buffer on the SMC-D teardown path
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: ae2be35cbe ("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: Sidraya Jayagond <sidraya@linux.ibm.com>
Reviewed-by: Tony Lu <tonylu@linux.alibaba.com>
Link: https://patch.msgid.link/20260808-b4-disp-22f119e6-v2-2-61647601a6f3@proton.me
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
36cdf5d48c
commit
b395dd319c
@@ -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 -
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user