From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pl1-f176.google.com (mail-pl1-f176.google.com [209.85.214.176]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 65FBC3FB075 for ; Tue, 9 Jun 2026 11:23:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.176 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781004212; cv=none; b=pgO8hoHv8QxxKoaBxgjXvkBmYWwCdTwS4tvBU9omb1XCTyCeuuaM0hthJr/TIlqhROZXsgjXR2/bgJjXzuqM5ybFPYCBEoOLq4KbOqOqWn+yERT1jKLxDW/Kf+K8ZTy/DJ/ev2vyKmQSwInho9yEx/1AqOuMUjh1Cu3qZ1ePyc8= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781004212; c=relaxed/simple; bh=P4XGoRQ5BTryg0GgBlPYvMJjZgaDdzAwmxXZAWkJolA=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=KUQaHkG2tSMJgIfc4XIdRWsSxosm1ZJluD2EkObNsHeyOylZU7D/npLJMW3Ez8xamiMF2Z3mV3VhRlRaXIN9Y6qOm0ODfF8vNgRbxrT9sZx+qNqISzc/3ogFfWf8cJSnHHbD3jN9G8dZ+mj4tVg4b3AcXRpH5ap6561ZTwUWfI8= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=CNom5odz; arc=none smtp.client-ip=209.85.214.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="CNom5odz" Received: by mail-pl1-f176.google.com with SMTP id d9443c01a7336-2bf20f6be6bso41568455ad.3 for ; Tue, 09 Jun 2026 04:23:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1781004211; x=1781609011; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=kk/KQ6BJWiQwzMAsi31u8EPjaiQOWvIKGyuiY9ezidI=; b=CNom5odz3fE7e6Jj4svbf81T5VRgXoNRKs+LDwHjmJr7UucLriuJSreP0Z1rKaCH11 tPv4WFy86coLOeaGJMuPXugf33TKxc51Qjp1tlfGuT3Nc5Sua5Dknd4473wwGmg3X258 VNbBJ/s4T+hmQ81b8M3n8j8AaIq2BdT0C1L+ctfXMcIOmGqVVI0grrRDNGDmVNuyYdHM kvQhuTFJgaZknEBG9FqDxS4ojwbT+qkslm2QskHF7jY5oKtfnG10Fd2LkU4vlWlx+a2Z aAWrVxoxMqzGTPoItzKYo3teshoyYdQyyN0SkKAfSn3Ahn3pxwCSRSGCP193eF2QREx5 Atzg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781004211; x=1781609011; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=kk/KQ6BJWiQwzMAsi31u8EPjaiQOWvIKGyuiY9ezidI=; b=pjv7uS3C1eHJHCGgfQsPvN3FsSizrQ6uwhaSC074e5PeThmytgSEe3oi5g/P7feb7R Swhb/1LbXmnw/3HCRozS8XR6RSvQmCMJF+IDth4ot/oaJ24bVUbzDoS6E37whmkQQIvA pYEZHKe17OiivYYCpBc2KQvCNiZ4qHjWsLmZmnpc94qeqRVhf1EmLvGRDc8eh6qmOg4q 06L/GpNA/C3Ep6ZwMb+sL+szHNpppIxDqETxaaIPYX8509MoVyURjxQ2eNyZ795HaR03 VqobjL5PCLZ32roJdVEbAPX1j0niLyIfcMxAEzOilN4B2kO2pQDQxRttXRQDU6+IVVO8 SMng== X-Forwarded-Encrypted: i=1; AFNElJ92+QCrB/vj4MJf1ug0ZwpGiQujZLaumQbQk4lxquiDrazQNesDew/QPb4bBlKV9eonciozm9ElFZRIOeY=@vger.kernel.org X-Gm-Message-State: AOJu0YxcWqlfDUPrNGhXEJ6nsQF/kUSZG3StI3yMCZF+89oVE24nAmzT FIWzKiWklts8YoPfvXrxsUINGd3mun/rzA5GccfEbZM6ZFgvDUqfyzlc X-Gm-Gg: Acq92OFjkMfJEPQLcnIkiqNew57gQ27AS8l7dhV7RRwzlkirjK5/piM5AYxuTzo5jqc MBAhe6LjfFEx+nwb7nYthbS5+0O1Pjx3DG88cPNLU7jnYICGKo+AXx0YfBGieSyIkx07z6Z5zAz 3JRk3gZUZ3MQglLgBw+AWW8C+T1B/55DpAapOA/qEFS9ErPxbvp86P/ZGxx7V28fCMy/vMhe1JH VGQsIoRtCGLZ9bQuukDt7fVpytjtS0m6pUFzRvyb2vyYudsXt5T8bWrP7HGf+wfg1LArRZmHPEo oTk0n/e6QhJMposZgzkeGYgupV1cDw0OCBgwxiiu2ec7ZZ0WgyIf8tsWsyJtxY8yJEkIJmlgbzX uE7yjfi0yB74vxknUQQ5HRbX2XsjeE/ztNhCQWZOq9O60b9758mYj/tv3X4O7jgi1Y2Rc72mHks 2GH/ov4ULAQQumcvVZb3DQBv5D/jm1peeIW3obAHoLfjHuQB4Pl/Cfr1RS922HLDrwj9nPZ+Ep X-Received: by 2002:a17:903:2342:b0:2bf:1486:e6ca with SMTP id d9443c01a7336-2c1e7d41eb6mr213499545ad.12.1781004210540; Tue, 09 Jun 2026 04:23:30 -0700 (PDT) Received: from cps-manycore-1.. ([147.46.174.222]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2c16649ab01sm202528565ad.71.2026.06.09.04.23.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 09 Jun 2026 04:23:30 -0700 (PDT) From: Sechang Lim To: John Fastabend , Jakub Sitnicki Cc: "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , netdev@vger.kernel.org, bpf@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH bpf] bpf, sockmap: fix use-after-free when the stream parser resizes the skb Date: Tue, 9 Jun 2026 11:23:03 +0000 Message-ID: <20260609112316.3685738-1-rhkrqnwk98@gmail.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit sk_psock_strp_parse() runs the BPF_PROG_TYPE_SK_SKB stream-parser program to find the length of the next message. strparser assembles a message out of several received skbs by chaining them onto the head's frag_list and recording where to append the next one in strp->skb_nextp: *strp->skb_nextp = skb; strp->skb_nextp = &skb->next; and then calls the parser on the head: len = (*strp->cb.parse_msg)(strp, head); The parser is only meant to inspect the skb, but the program may call bpf_skb_change_tail() -- or the sibling bpf_skb_pull_data(), bpf_skb_change_head(), bpf_skb_adjust_room(), all allowed for SK_SKB. Once the head carries a frag_list these go ... -> skb_ensure_writable -> pskb_may_pull -> __pskb_pull_tail and __pskb_pull_tail() frees the frag_list skbs that strparser still tracks through skb_nextp: while ((list = skb_shinfo(skb)->frag_list) != insp) { skb_shinfo(skb)->frag_list = list->next; consume_skb(list); } strp->skb_nextp now points into a freed sk_buff. The next segment of the same message arrives in __strp_recv(), which links it with *strp->skb_nextp = skb, an 8-byte write into the freed skb. The free and the write happen in different __strp_recv() calls, so the message has to span at least three segments before it triggers. BUG: KASAN: slab-use-after-free in __strp_recv+0x447/0xda0 Write of size 8 at addr ffff88810db86140 by task repro/349 Call Trace: __strp_recv+0x447/0xda0 __tcp_read_sock+0x13d/0x590 tcp_bpf_strp_read_sock+0x195/0x320 strp_data_ready+0x267/0x340 sk_psock_strp_data_ready+0x1ce/0x350 tcp_data_queue+0x1364/0x2fd0 tcp_rcv_established+0xe07/0x1640 [...] Allocated by task 349: skb_clone+0x17b/0x210 __strp_recv+0x2c3/0xda0 __tcp_read_sock+0x13d/0x590 [...] Freed by task 349: kmem_cache_free+0x150/0x570 __pskb_pull_tail+0x57b/0xc20 skb_ensure_writable+0x236/0x260 __bpf_skb_change_tail+0x1d4/0x590 sk_skb_change_tail+0x2a/0x40 bpf_prog_1b285dcd6c41373e+0x27/0x30 bpf_prog_run_pin_on_cpu+0xf3/0x260 sk_psock_strp_parse+0x118/0x1e0 __strp_recv+0x4f6/0xda0 [...] The same resize also leaves the head's length inconsistent with its frags, so a later __pskb_pull_tail() can instead hit the BUG_ON(skb_copy_bits(...)) in net/core/skbuff.c. Run the parser on a private clone of the head whenever the message spans more than one skb, so a resizing helper can only touch the clone and strparser's head and skb_nextp stay valid. Single-skb messages have no frag_list and are still parsed in place. Fixes: 8a31db561566 ("bpf: add access to sock fields and pkt data from sk_skb programs") Signed-off-by: Sechang Lim --- net/core/skmsg.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/net/core/skmsg.c b/net/core/skmsg.c index e1850caf1a71..d5b10f9b0ba8 100644 --- a/net/core/skmsg.c +++ b/net/core/skmsg.c @@ -1146,14 +1146,30 @@ static int sk_psock_strp_parse(struct strparser *strp, struct sk_buff *skb) struct bpf_prog *prog; int ret = skb->len; - rcu_read_lock(); + guard(rcu)(); prog = READ_ONCE(psock->progs.stream_parser); if (likely(prog)) { - skb->sk = psock->sk; - ret = bpf_prog_run_pin_on_cpu(prog, skb); - skb->sk = NULL; + struct sk_buff *parse_skb = skb; + + /* + * strparser chains the message skbs through skb->frag_list and + * keeps a pointer into that list in strp->skb_nextp. The parser + * program may call bpf_skb_change_tail() and friends, which go + * through __pskb_pull_tail() and free the frag_list skbs that + * strparser still tracks. Run the program on a clone when a + * frag_list is present so it cannot drop frags strparser owns. + */ + if (skb_has_frag_list(skb)) { + parse_skb = skb_clone(skb, GFP_ATOMIC); + if (!parse_skb) + return -ENOMEM; + } + parse_skb->sk = psock->sk; + ret = bpf_prog_run_pin_on_cpu(prog, parse_skb); + parse_skb->sk = NULL; + if (parse_skb != skb) + kfree_skb(parse_skb); } - rcu_read_unlock(); return ret; } -- 2.43.0