mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 14:04:27 -04:00
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:
committed by
Jakub Kicinski
parent
7b196e27ad
commit
9466ef3ec9
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user