mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
tls: device: protect async RX resync state during device-down
tls_device_rx_resync_new_rec() can run in process context with the
socket lock held, but without an RCU read lock: from the strparser work
item (tls_strp_work()) and from the receive paths (tls_rx_rec_wait(),
tls_rx_rec_done()). The resync_async pointer belongs to the driver RX
context, which tls_device_down() tears down from the netdev notifier
without taking the socket lock; only the softirq entry to the parser is
implicitly inside an RCU section.
If the parser passes the TLS_RX_DEV_DEGRADED check before device-down
sets it, tls_device_down() can complete synchronize_net() and delete the
driver context before the parser accesses resync_async->req or its
record log. In the asynchronous stage the parser also writes the record
log, so this is a write to freed memory, not only a stale read. The RCU
section in tls_device_resync_rx() starts after those accesses and
therefore does not prevent the use-after-free.
Found by code inspection; not reproduced. Hitting the window requires
the parser to be preempted between the DEGRADED check and the
resync_async access across the device-down grace period and the
driver's teardown.
Fixes: ed9b7646b0 ("net/tls: Add asynchronous resync")
Signed-off-by: Rishikesh Jethwani <rjethwani@purestorage.com>
Link: https://patch.msgid.link/20261013213517.2219663-1-rjethwani@purestorage.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
56f8d91973
commit
f89a228125
|
|
@ -783,8 +783,15 @@ void tls_device_rx_resync_new_rec(struct sock *sk, u32 rcd_len, u32 seq)
|
|||
|
||||
if (tls_ctx->rx_conf != TLS_HW)
|
||||
return;
|
||||
|
||||
/* The parser also runs in process context, without an RCU read lock.
|
||||
* Protect the driver's resync_async state before checking the flags:
|
||||
* device-down sets DEGRADED and waits for synchronize_net() before
|
||||
* freeing it, without taking the socket lock.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
if (unlikely(test_bit(TLS_RX_DEV_DEGRADED, &tls_ctx->flags)))
|
||||
return;
|
||||
goto out;
|
||||
|
||||
prot = &tls_ctx->prot_info;
|
||||
rx_ctx = tls_offload_ctx_rx(tls_ctx);
|
||||
|
|
@ -799,11 +806,11 @@ void tls_device_rx_resync_new_rec(struct sock *sk, u32 rcd_len, u32 seq)
|
|||
|
||||
if (likely(!is_req_pending) || req_seq != seq ||
|
||||
!atomic64_try_cmpxchg(&rx_ctx->resync_req, &resync_req, 0))
|
||||
return;
|
||||
goto out;
|
||||
break;
|
||||
case TLS_OFFLOAD_SYNC_TYPE_CORE_NEXT_HINT:
|
||||
if (likely(!rx_ctx->resync_nh_do_now))
|
||||
return;
|
||||
goto out;
|
||||
|
||||
/* head of next rec is already in, note that the sock_inq will
|
||||
* include the currently parsed message when called from parser
|
||||
|
|
@ -812,7 +819,7 @@ void tls_device_rx_resync_new_rec(struct sock *sk, u32 rcd_len, u32 seq)
|
|||
if (sock_data > rcd_len) {
|
||||
trace_tls_device_rx_resync_nh_delay(sk, sock_data,
|
||||
rcd_len);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rx_ctx->resync_nh_do_now = 0;
|
||||
|
|
@ -823,16 +830,18 @@ void tls_device_rx_resync_new_rec(struct sock *sk, u32 rcd_len, u32 seq)
|
|||
resync_req = atomic64_read(&rx_ctx->resync_async->req);
|
||||
is_req_pending = resync_req;
|
||||
if (likely(!is_req_pending))
|
||||
return;
|
||||
goto out;
|
||||
|
||||
if (!tls_device_rx_resync_async(rx_ctx->resync_async,
|
||||
resync_req, &seq, &rcd_delta))
|
||||
return;
|
||||
goto out;
|
||||
tls_bigint_subtract(rcd_sn, rcd_delta);
|
||||
break;
|
||||
}
|
||||
|
||||
tls_device_resync_rx(tls_ctx, sk, seq, rcd_sn);
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void tls_device_core_ctrl_rx_resync(struct tls_context *tls_ctx,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user