* [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; 7+ 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] 7+ 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; 7+ 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] 7+ 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; 7+ 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] 7+ 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; 7+ 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] 7+ 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 2026-06-19 1:54 ` Sechang Lim 0 siblings, 1 reply; 7+ 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] 7+ 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 18:01 ` John Fastabend @ 2026-06-19 1:54 ` Sechang Lim 0 siblings, 0 replies; 7+ messages in thread From: Sechang Lim @ 2026-06-19 1:54 UTC (permalink / raw) To: John Fastabend; +Cc: Jiayuan Chen, netdev, bpf, linux-kernel, Jakub Kicinski On Thu, Jun 18, 2026 at 11:01:58AM -0700, John Fastabend wrote: >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. Thanks for your review, dropping the Fixes tag in v4. >> >> >>>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. Thanks for your review. Will do in v4. Best, Sechang ^ permalink raw reply [flat|nested] 7+ 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; 7+ 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] 7+ messages in thread
end of thread, other threads:[~2026-06-19 1:54 UTC | newest] Thread overview: 7+ 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-19 1:54 ` 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
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.