[PATCH net-next v17 08/15] tcp: fence collapse against rtx-queue tail when write queue is empty
From: Rishikesh Jethwani <hidden>
Date: 2026-09-17 22:45:20
Subsystem:
networking [general], networking [tcp], the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Neal Cardwell, Linus Torvalds
tcp_write_collapse_fence() marks the current write-queue tail as
end-of-record so a later tcp_retrans_try_collapse() / tcp_shift_skb_data()
does not merge across the fence. When nothing is queued for transmit the
write queue is empty, and the last skb of the current state is the
retransmit-queue tail (its end_seq == snd_nxt == write_seq); fence that
instead. Otherwise the boundary is left unmarked and a later collapse can
merge it with the first skb of the next state across the fence, since
those paths test only the tail's EOR, not skb->decrypted.
This is a critical fix for both TLS device offload and PSP (PSP Security
Protocol). Both use skb->decrypted to mark encrypted/transformed packets:
pre-key skbs stay decrypted=0, post-key skbs are decrypted=1. A collapse
can merge a post-key skb into a pre-key skb, whose decrypted=0 causes the
driver to send the post-key payload in cleartext.
The write-queue-empty case is the common state at the time encryption
keys are installed (tls_set_device_offload() setsockopt and
psp_sock_set_tx_key() in PSP), when the previous handshake or request
has just finished and nothing is being sent. The existing fence is a
no-op there (write_queue_tail is NULL), leaving the boundary unmarked.
A later retransmit of the final pre-key handshake record can then
collapse against new post-key data via tcp_retrans_try_collapse() or
SACK-driven tcp_shift_skb_data(), leaking the post-key payload in
cleartext.
This fix makes tcp_write_collapse_fence() fence the rtx-queue tail when
the write queue is empty, blocking the merge. TLS 1.3 device-offload
KeyUpdate additionally relies on this behavior to keep old-key and
new-key records in distinct skbs for re-encryption on RX.
Fixes: 1be68a87ab33 ("tcp: add a helper for setting EOR on tail skb")
Signed-off-by: Rishikesh Jethwani <redacted>
---
include/net/tcp.h | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 5e5f5f9b89a3..8c6d90e962c4 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h@@ -2340,6 +2340,15 @@ static inline void tcp_write_collapse_fence(struct sock *sk) { struct sk_buff *skb = tcp_write_queue_tail(sk); + /* When nothing is queued for transmit, the last skb of the current + * state is the rtx queue tail (its end_seq == snd_nxt == write_seq). + * Fence that instead, otherwise the boundary is left unmarked and a + * later tcp_retrans_try_collapse()/tcp_shift_skb_data() can merge it + * with the first skb of the next state across the fence (they only test + * the tail's EOR, not skb->decrypted). + */ + if (!skb) + skb = tcp_rtx_queue_tail(sk); if (skb) TCP_SKB_CB(skb)->eor = 1; }
--
2.50.1