* [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
* [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
* 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
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 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.