tls: fix RX desync on overlapping skbs

The TCP receive queue can hold adjacent skbs whose sequence ranges
overlap. The tls fast-path reads the record header with skb_copy_bits()
by byte offset, which assumes skbs do not overlap, so a header split
across the overlap is misread and the connection aborts
(-EMSGSIZE/-EINVAL). tls_strp_check_queue_ok() detects such overlaps but
only ran after the header was parsed, never covering the header itself.

Observed with parallel kTLS connections on:
- ConnectX-7 + IPsec crypto offload + GRO
- VirtIO (8 queues) + GRO

Fixes: 84c61fe1a7 ("tls: rx: do not use the standard strparser")
Signed-off-by: Maximilian Immanuel Brandtner <maxbr@linux.ibm.com>
Link: https://patch.msgid.link/20260813121337.3300688-1-maxbr@linux.ibm.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Maximilian Immanuel Brandtner
2026-08-13 14:09:44 +02:00
committed by Jakub Kicinski
parent 7b196e27ad
commit 9466ef3ec9

View File

@@ -430,9 +430,10 @@ static int tls_strp_read_copy(struct tls_strparser *strp, bool qshort)
return 0;
}
static bool tls_strp_check_queue_ok(struct tls_strparser *strp)
static bool tls_strp_check_queue_ok(struct tls_strparser *strp,
unsigned int len)
{
unsigned int len = strp->stm.offset + strp->stm.full_len;
unsigned int remaining = strp->stm.offset + len;
struct sk_buff *first, *skb;
u32 seq;
@@ -443,9 +444,9 @@ static bool tls_strp_check_queue_ok(struct tls_strparser *strp)
/* Make sure there's no duplicate data in the queue,
* and the decrypted status matches.
*/
while (skb->len < len) {
while (skb->len < remaining) {
seq += skb->len;
len -= skb->len;
remaining -= skb->len;
skb = skb->next;
if (TCP_SKB_CB(skb)->seq != seq)
@@ -525,6 +526,11 @@ static int tls_strp_read_sock(struct tls_strparser *strp)
tls_strp_load_anchor_with_queue(strp, inq);
if (!strp->stm.full_len) {
if (inq < TLS_HEADER_SIZE)
return tls_strp_read_copy(strp, true);
if (!tls_strp_check_queue_ok(strp, TLS_HEADER_SIZE))
return tls_strp_read_copy(strp, false);
sz = tls_rx_msg_size(strp, strp->anchor);
if (sz < 0)
return sz;
@@ -535,7 +541,7 @@ static int tls_strp_read_sock(struct tls_strparser *strp)
return tls_strp_read_copy(strp, true);
}
if (!tls_strp_check_queue_ok(strp))
if (!tls_strp_check_queue_ok(strp, strp->stm.full_len))
return tls_strp_read_copy(strp, false);
WRITE_ONCE(strp->msg_ready, 1);