Re: [PATCH net] tls: fix RX desync on overlapping skbs
From: Jakub Kicinski <kuba@kernel.org>
Date: 2026-08-12 02:33:45
On Fri, 7 Aug 2026 19:31:05 +0200 Maximilian Immanuel Brandtner wrote:
On a reordering path (e.g. IPsec crypto offload + GRO) the TCP receive
It'd be better to move this "IPsec crypto offload + GRO" to the end, it's not super relevant to the problem. Mention that you observe this in real life and that "IPsec crypto offload + GRO" is the likely culprit. Mentioning the NIC may also be useful to other users.
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 skb ranges don't overlap. When a record boundary lands within the last few bytes of an skb, the 5-byte header straddles into the overlapping next skb; the duplicate bytes are read as the header, yielding a bogus length (-EMSGSIZE) or version (-EINVAL) and aborting the connection. tls_strp_check_queue_ok() already detects such overlaps and diverts to the seq-addressed copy path, but it only ran after the header was parsed,
The rest of this paragraph below looks like slop, don't describe what the patch does. We can hopefully see that from the diff.
quoted hunk ↗ jump to hunk
and it validated stm.offset + stm.full_len -- and full_len is still 0 for a new record, so it could not cover the header bytes. Parameterize it by length and also validate the header region (stm.offset + TLS_HEADER_SIZE) before parsing. Fixes: 84c61fe1a75b ("tls: rx: do not use the standard strparser") Signed-off-by: Maximilian Immanuel Brandtner <redacted> --- Tested on Linux kernel 7.2 rc6 --- net/tls/tls_strp.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c index 61b10c697ecc..64d5dea90540 100644 --- a/net/tls/tls_strp.c +++ b/net/tls/tls_strp.c@@ -430,9 +430,9 @@ 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;
keep the stm.offset addition here, it's doesn't belong in the caller
quoted hunk ↗ jump to hunk
struct sk_buff *first, *skb; u32 seq;@@ -525,6 +525,12 @@ 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); +
no empty line between the two checks
+ if (!tls_strp_check_queue_ok(strp, strp->stm.offset + TLS_HEADER_SIZE)) + return tls_strp_read_copy(strp, false);