* [PATCH bpf v3 0/2] bpf, sockmap: reject a packet-modifying SK_SKB stream parser
@ 2026-06-18 10:27 Sechang Lim
2026-06-18 10:27 ` [PATCH bpf v3 1/2] bpf, sockmap: fix use-after-free when the stream parser resizes the skb Sechang Lim
2026-06-18 10:27 ` [PATCH bpf v3 2/2] selftests/bpf: test rejection of a packet-modifying SK_SKB stream parser Sechang Lim
0 siblings, 2 replies; 6+ messages in thread
From: Sechang Lim @ 2026-06-18 10:27 UTC (permalink / raw)
To: John Fastabend, Jakub Sitnicki, Eric Dumazet, Kuniyuki Iwashima,
Paolo Abeni, Willem de Bruijn, David S . Miller, Jakub Kicinski
Cc: Simon Horman, Bobby Eshleman, Jiayuan Chen, netdev, bpf,
linux-kernel
A BPF_PROG_TYPE_SK_SKB stream parser runs on strparser's message head,
which can chain skbs through frag_list. A parser that resizes the skb
frees the frag_list segments that strparser still tracks through
skb_nextp, leading to a use-after-free.
A stream parser is only meant to measure the next message, not to modify
the packet, so reject a packet-modifying parser at attach time rather
than working around the resize at runtime.
v3:
- reject the parser at attach time instead of cloning the skb at
runtime (Kuniyuki Iwashima, Jiayuan Chen)
- add a selftest (Bobby Eshleman)
v2:
- https://lore.kernel.org/all/20260612123553.2724240-1-rhkrqnwk98@gmail.com/
v1:
- https://lore.kernel.org/all/20260609112316.3685738-1-rhkrqnwk98@gmail.com/
Sechang Lim (2):
bpf, sockmap: fix use-after-free when the stream parser resizes the
skb
selftests/bpf: test rejection of a packet-modifying SK_SKB stream
parser
net/core/sock_map.c | 20 ++++++++++++
.../selftests/bpf/prog_tests/sockmap_strp.c | 31 +++++++++++++++++++
.../selftests/bpf/progs/test_sockmap_strp.c | 7 +++++
3 files changed, 58 insertions(+)
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH bpf v3 1/2] bpf, sockmap: fix use-after-free when the stream parser resizes the skb 2026-06-18 10:27 [PATCH bpf v3 0/2] bpf, sockmap: reject a packet-modifying SK_SKB stream parser Sechang Lim @ 2026-06-18 10:27 ` Sechang Lim 2026-06-18 10:59 ` sashiko-bot 2026-06-18 11:56 ` Jiayuan Chen 2026-06-18 10:27 ` [PATCH bpf v3 2/2] selftests/bpf: test rejection of a packet-modifying SK_SKB stream parser Sechang Lim 1 sibling, 2 replies; 6+ messages in thread From: Sechang Lim @ 2026-06-18 10:27 UTC (permalink / raw) To: John Fastabend, Jakub Sitnicki, Eric Dumazet, Kuniyuki Iwashima, Paolo Abeni, Willem de Bruijn, David S . Miller, Jakub Kicinski Cc: Simon Horman, Bobby Eshleman, Jiayuan Chen, netdev, bpf, linux-kernel 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: <IRQ> __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. A stream parser is only meant to measure the next message, not to modify the packet. Reject a parser whose program can change packet data (prog->aux->changes_pkt_data) at attach time. The check is shared by sock_map_prog_update() and sock_map_link_update_prog(), which between them cover prog attach, link create and link update. Verdict programs are unaffected and may still modify the skb. Fixes: 8a31db561566 ("bpf: add access to sock fields and pkt data from sk_skb programs") Signed-off-by: Sechang Lim <rhkrqnwk98@gmail.com> --- net/core/sock_map.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/net/core/sock_map.c b/net/core/sock_map.c index 99e3789492a0..c60ba6d292f9 100644 --- a/net/core/sock_map.c +++ b/net/core/sock_map.c @@ -1515,6 +1515,17 @@ static int sock_map_prog_link_lookup(struct bpf_map *map, struct bpf_prog ***ppr return 0; } +static int sock_map_prog_attach_check(enum bpf_attach_type attach_type, + struct bpf_prog *prog) +{ + /* A stream parser must not modify the skb, only measure it. */ + if (prog && attach_type == BPF_SK_SKB_STREAM_PARSER && + prog->aux->changes_pkt_data) + return -EINVAL; + + return 0; +} + /* Handle the following four cases: * prog_attach: prog != NULL, old == NULL, link == NULL * prog_detach: prog == NULL, old != NULL, link == NULL @@ -1533,6 +1544,10 @@ static int sock_map_prog_update(struct bpf_map *map, struct bpf_prog *prog, if (ret) return ret; + ret = sock_map_prog_attach_check(which, prog); + if (ret) + return ret; + /* for prog_attach/prog_detach/link_attach, return error if a bpf_link * exists for that prog. */ @@ -1776,6 +1791,11 @@ static int sock_map_link_update_prog(struct bpf_link *link, ret = -EINVAL; goto out; } + + ret = sock_map_prog_attach_check(link->attach_type, prog); + if (ret) + goto out; + if (!sockmap_link->map) { ret = -ENOLINK; goto out; -- 2.43.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH bpf v3 1/2] bpf, sockmap: fix use-after-free when the stream parser resizes the skb 2026-06-18 10:27 ` [PATCH bpf v3 1/2] bpf, sockmap: fix use-after-free when the stream parser resizes the skb Sechang Lim @ 2026-06-18 10:59 ` sashiko-bot 2026-06-18 11:56 ` Jiayuan Chen 1 sibling, 0 replies; 6+ messages in thread From: sashiko-bot @ 2026-06-18 10:59 UTC (permalink / raw) To: Sechang Lim; +Cc: bpf Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: Pre-existing issues: - [Critical] The patch attempts to fix a slab-use-after-free by rejecting stream parser programs that modify the SKB, relying on `prog->aux->changes_pkt_data`. However, this flag does not account for `bpf_dynptr_write`, which also modifies the SKB and triggers the exact same use-after-free vulnerability. -- commit aeac0d3c109078049124a26f6151db8a79f11ac5 Author: Sechang Lim <rhkrqnwk98@gmail.com> bpf, sockmap: fix use-after-free when the stream parser resizes the skb This patch rejects stream parser programs that modify packet data to prevent a use-after-free. The issue occurs when skb_ensure_writable() frees the frag_list that the stream parser continues to track. > diff --git a/net/core/sock_map.c b/net/core/sock_map.c > index 99e3789492a09..c60ba6d292f9a 100644 > --- a/net/core/sock_map.c > +++ b/net/core/sock_map.c [ ... ] > @@ -1515,6 +1515,17 @@ static int sock_map_prog_link_lookup(struct bpf_map *map, struct bpf_prog ***ppr > return 0; > } > > +static int sock_map_prog_attach_check(enum bpf_attach_type attach_type, > + struct bpf_prog *prog) > +{ > + /* A stream parser must not modify the skb, only measure it. */ > + if (prog && attach_type == BPF_SK_SKB_STREAM_PARSER && > + prog->aux->changes_pkt_data) [Severity: Critical] This isn't a bug introduced by this patch, but does this check completely prevent the vulnerability? It appears that prog->aux->changes_pkt_data might be bypassed if a program uses bpf_dynptr_write(). Looking at bpf_helper_changes_pkt_data() in net/core/filter.c, BPF_FUNC_dynptr_write is missing from the switch statement. Consequently, the verifier does not set prog->aux->changes_pkt_data during CFG construction for programs that write via dynptrs. While the verifier sets a local changes_data flag in check_helper_call() to clear packet pointers: kernel/bpf/verifier.c:check_helper_call() { ... /* this will trigger clear_all_pkt_pointers(), which will * invalidate all dynptr slices associated with the skb */ changes_data = true; ... } It never sets the permanent env->subprog_info[...].changes_pkt_data flag for this helper. Could a malicious BPF_PROG_TYPE_SK_SKB program use bpf_dynptr_from_skb() to get a writable dynptr, and then call bpf_dynptr_write() to invoke skb_ensure_writable() and free the frag_list? If so, would this trigger the exact same use-after-free, completely bypassing this attach-time check? > + return -EINVAL; > + > + return 0; > +} [ ... ] -- Sashiko AI review · https://sashiko.dev/#/patchset/20260618102718.2331468-1-rhkrqnwk98@gmail.com?part=1 ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH bpf v3 1/2] bpf, sockmap: fix use-after-free when the stream parser resizes the skb 2026-06-18 10:27 ` [PATCH bpf v3 1/2] bpf, sockmap: fix use-after-free when the stream parser resizes the skb Sechang Lim 2026-06-18 10:59 ` sashiko-bot @ 2026-06-18 11:56 ` Jiayuan Chen 2026-06-18 18:01 ` John Fastabend 1 sibling, 1 reply; 6+ messages in thread From: Jiayuan Chen @ 2026-06-18 11:56 UTC (permalink / raw) To: John Fastabend; +Cc: netdev, bpf, linux-kernel, Jakub Kicinski, Sechang Lim On 6/18/26 6:27 PM, Sechang Lim wrote: > 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); [...] > unaffected and may still modify the skb. > > Fixes: 8a31db561566 ("bpf: add access to sock fields and pkt data from sk_skb programs") Is the Fixes tag correct ? Anyway, I don't think this patch is a fix; it's more of a hardening. So no Fixes tag needed, IMO. > Signed-off-by: Sechang Lim <rhkrqnwk98@gmail.com> > --- > net/core/sock_map.c | 20 ++++++++++++++++++++ > 1 file changed, 20 insertions(+) > > diff --git a/net/core/sock_map.c b/net/core/sock_map.c > index 99e3789492a0..c60ba6d292f9 100644 > --- a/net/core/sock_map.c > +++ b/net/core/sock_map.c > @@ -1515,6 +1515,17 @@ static int sock_map_prog_link_lookup(struct bpf_map *map, struct bpf_prog ***ppr > return 0; > } > > +static int sock_map_prog_attach_check(enum bpf_attach_type attach_type, > + struct bpf_prog *prog) > +{ > + /* A stream parser must not modify the skb, only measure it. */ > + if (prog && attach_type == BPF_SK_SKB_STREAM_PARSER && > + prog->aux->changes_pkt_data) > + return -EINVAL; > + > + return 0; > +} > + > /* Handle the following four cases: > * prog_attach: prog != NULL, old == NULL, link == NULL > * prog_detach: prog == NULL, old != NULL, link == NULL > @@ -1533,6 +1544,10 @@ static int sock_map_prog_update(struct bpf_map *map, struct bpf_prog *prog, > if (ret) > return ret; > > + ret = sock_map_prog_attach_check(which, prog); > + if (ret) > + return ret; > + > /* for prog_attach/prog_detach/link_attach, return error if a bpf_link > * exists for that prog. > */ > @@ -1776,6 +1791,11 @@ static int sock_map_link_update_prog(struct bpf_link *link, > ret = -EINVAL; > goto out; > } > + > + ret = sock_map_prog_attach_check(link->attach_type, prog); > + if (ret) > + goto out; > + > if (!sockmap_link->map) { > ret = -ENOLINK; > goto out; CI failed: https://github.com/kernel-patches/bpf/actions/runs/27754218839/job/82113319982 Failed stream parser bpf prog attach Hi John I noticed that bpf_skb_pull_data was added to the skmsg test: https://github.com/torvalds/linux/commit/82a8616889d506cb690cfc0afb2ccadda120461d Can we drop bpf_skb_pull_data in parser prog(sockmap_parse_prog.c) ? And are there any scenarios where we need to modify skb len when using strparser ? ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH bpf v3 1/2] bpf, sockmap: fix use-after-free when the stream parser resizes the skb 2026-06-18 11:56 ` Jiayuan Chen @ 2026-06-18 18:01 ` John Fastabend 0 siblings, 0 replies; 6+ messages in thread From: John Fastabend @ 2026-06-18 18:01 UTC (permalink / raw) To: Jiayuan Chen; +Cc: netdev, bpf, linux-kernel, Jakub Kicinski, Sechang Lim On Thu, Jun 18, 2026 at 07:56:34PM +0800, Jiayuan Chen wrote: > >On 6/18/26 6:27 PM, Sechang Lim wrote: >>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); > >[...] > >>unaffected and may still modify the skb. >> >>Fixes: 8a31db561566 ("bpf: add access to sock fields and pkt data from sk_skb programs") > >Is the Fixes tag correct ? > >Anyway, I don't think this patch is a fix; it's more of a hardening. >So no Fixes tag needed, IMO. > > >>Signed-off-by: Sechang Lim <rhkrqnwk98@gmail.com> >>--- [...] > > >CI failed: >https://github.com/kernel-patches/bpf/actions/runs/27754218839/job/82113319982 > Failed stream parser bpf prog attach > >Hi John >I noticed that bpf_skb_pull_data was added to the skmsg test: >https://github.com/torvalds/linux/commit/82a8616889d506cb690cfc0afb2ccadda120461d > >Can we drop bpf_skb_pull_data in parser prog(sockmap_parse_prog.c) ? >And are there any scenarios where we need to modify skb len when using >strparser ? We should never modify the skb from strparser. Just remove any tests that do this and state its not safe. We haven't used strparser progs for a long time anyways. ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH bpf v3 2/2] selftests/bpf: test rejection of a packet-modifying SK_SKB stream parser 2026-06-18 10:27 [PATCH bpf v3 0/2] bpf, sockmap: reject a packet-modifying SK_SKB stream parser Sechang Lim 2026-06-18 10:27 ` [PATCH bpf v3 1/2] bpf, sockmap: fix use-after-free when the stream parser resizes the skb Sechang Lim @ 2026-06-18 10:27 ` Sechang Lim 1 sibling, 0 replies; 6+ messages in thread From: Sechang Lim @ 2026-06-18 10:27 UTC (permalink / raw) To: John Fastabend, Jakub Sitnicki, Eric Dumazet, Kuniyuki Iwashima, Paolo Abeni, Willem de Bruijn, David S . Miller, Jakub Kicinski Cc: Simon Horman, Bobby Eshleman, Jiayuan Chen, netdev, bpf, linux-kernel Verify that attaching an SK_SKB stream parser that can modify the packet is rejected, while a read-only parser still attaches. Signed-off-by: Sechang Lim <rhkrqnwk98@gmail.com> --- .../selftests/bpf/prog_tests/sockmap_strp.c | 31 +++++++++++++++++++ .../selftests/bpf/progs/test_sockmap_strp.c | 7 +++++ 2 files changed, 38 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_strp.c b/tools/testing/selftests/bpf/prog_tests/sockmap_strp.c index 621b3b71888e..1d7231728eaf 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockmap_strp.c +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_strp.c @@ -431,6 +431,35 @@ static void test_sockmap_strp_verdict(int family, int sotype) test_sockmap_strp__destroy(strp); } +static void test_sockmap_strp_parser_reject(void) +{ + struct test_sockmap_strp *strp = NULL; + int parser_mod, parser_ro, link; + int err, map; + + strp = test_sockmap_strp__open_and_load(); + if (!ASSERT_OK_PTR(strp, "test_sockmap_strp__open_and_load")) + return; + + map = bpf_map__fd(strp->maps.sock_map); + parser_mod = bpf_program__fd(strp->progs.prog_skb_parser_resize); + parser_ro = bpf_program__fd(strp->progs.prog_skb_parser); + + err = bpf_prog_attach(parser_mod, map, BPF_SK_SKB_STREAM_PARSER, 0); + ASSERT_ERR(err, "bpf_prog_attach parser_mod"); + + link = bpf_link_create(parser_ro, map, BPF_SK_SKB_STREAM_PARSER, NULL); + if (!ASSERT_GE(link, 0, "bpf_link_create parser_ro")) + goto out; + + err = bpf_link_update(link, parser_mod, NULL); + ASSERT_ERR(err, "bpf_link_update parser_mod"); +out: + if (link >= 0) + close(link); + test_sockmap_strp__destroy(strp); +} + void test_sockmap_strp(void) { if (test__start_subtest("sockmap strp tcp pass")) @@ -451,4 +480,6 @@ void test_sockmap_strp(void) test_sockmap_strp_multiple_pkt(AF_INET, SOCK_STREAM); if (test__start_subtest("sockmap strp tcp dispatch")) test_sockmap_strp_dispatch_pkt(AF_INET, SOCK_STREAM); + if (test__start_subtest("sockmap strp parser reject pkt mod")) + test_sockmap_strp_parser_reject(); } diff --git a/tools/testing/selftests/bpf/progs/test_sockmap_strp.c b/tools/testing/selftests/bpf/progs/test_sockmap_strp.c index dde3d5bec515..fe88fa6d40bc 100644 --- a/tools/testing/selftests/bpf/progs/test_sockmap_strp.c +++ b/tools/testing/selftests/bpf/progs/test_sockmap_strp.c @@ -50,4 +50,11 @@ int prog_skb_parser_partial(struct __sk_buff *skb) return 10; } +SEC("sk_skb/stream_parser") +int prog_skb_parser_resize(struct __sk_buff *skb) +{ + bpf_skb_change_tail(skb, skb->len, 0); + return skb->len; +} + char _license[] SEC("license") = "GPL"; -- 2.43.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-06-18 18:02 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-06-18 10:27 [PATCH bpf v3 0/2] bpf, sockmap: reject a packet-modifying SK_SKB stream parser Sechang Lim 2026-06-18 10:27 ` [PATCH bpf v3 1/2] bpf, sockmap: fix use-after-free when the stream parser resizes the skb Sechang Lim 2026-06-18 10:59 ` sashiko-bot 2026-06-18 11:56 ` Jiayuan Chen 2026-06-18 18:01 ` John Fastabend 2026-06-18 10:27 ` [PATCH bpf v3 2/2] selftests/bpf: test rejection of a packet-modifying SK_SKB stream parser Sechang Lim
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox