mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
Merge branch 'net-smc-fix-use-after-free-in-smc_rx_pipe_buf_release'
Hidayath Khan says: ==================== net/smc: fix use-after-free in smc_rx_pipe_buf_release() smc_rx_pipe_buf_release() tests sk_state before taking the socket lock and then dereferences conn->rmb_desc and conn->lgr. A concurrent close runs smc_conn_free() in between, which releases those structures. On the is_reg_err path smcr_buf_unuse() frees the descriptor outright, so this is a use-after-free. Patch 2/2 fixes this by taking the socket lock first and testing conn->freed instead. smc_conn_free() sets that flag before releasing anything, under the same lock, so the two paths exclude each other. Patch 1/2 is a prerequisite. conn->freed shares a byte with killed and out_of_sync as single-bit bitfields. out_of_sync is written from the receive tasklet without the socket lock, so a concurrent store to freed from process context can be lost in the read-modify-write. Patch 1/2 gives each flag its own byte so stores do not interfere. ==================== Link: https://patch.msgid.link/20260820074642.966856-1-hidayath@linux.ibm.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
c745d091fc
|
|
@ -277,9 +277,9 @@ struct smc_connection {
|
|||
* 0 for SMC-R, 32 for SMC-D
|
||||
*/
|
||||
u64 peer_token; /* SMC-D token of peer */
|
||||
u8 killed : 1; /* abnormal termination */
|
||||
u8 freed : 1; /* normal termination */
|
||||
u8 out_of_sync : 1; /* out of sync with peer */
|
||||
u8 killed; /* abnormal termination */
|
||||
u8 freed; /* normal termination */
|
||||
u8 out_of_sync; /* out of sync with peer */
|
||||
};
|
||||
|
||||
struct smc_sock { /* smc sock container */
|
||||
|
|
|
|||
|
|
@ -115,16 +115,15 @@ static void smc_rx_pipe_buf_release(struct pipe_inode_info *pipe,
|
|||
struct pipe_buffer *buf)
|
||||
{
|
||||
struct smc_spd_priv *priv = (struct smc_spd_priv *)buf->private;
|
||||
struct smc_connection *conn = &priv->smc->conn;
|
||||
struct smc_sock *smc = priv->smc;
|
||||
struct smc_connection *conn;
|
||||
struct sock *sk = &smc->sk;
|
||||
|
||||
if (sk->sk_state == SMC_CLOSED ||
|
||||
sk->sk_state == SMC_PEERFINCLOSEWAIT ||
|
||||
sk->sk_state == SMC_APPFINCLOSEWAIT)
|
||||
goto out;
|
||||
conn = &smc->conn;
|
||||
lock_sock(sk);
|
||||
if (conn->freed) {
|
||||
release_sock(sk);
|
||||
goto out;
|
||||
}
|
||||
smc_rx_update_cons(smc, priv->len);
|
||||
release_sock(sk);
|
||||
if (atomic_sub_and_test(priv->len, &conn->splice_pending))
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user