* Re: [PATCH bpf-next v2 26/43] bpf: Don't take an extension for an iterator program
@ 2026-10-17 22:06 Tyrone Wu
2026-10-18 0:39 ` Alexei Starovoitov
0 siblings, 1 reply; 4+ messages in thread
From: Tyrone Wu @ 2026-10-17 22:06 UTC (permalink / raw)
To: alexei.starovoitov
Cc: andrii, bpf, daniel, eddyz87, josef, mason, memxor, netdev
Hi, I originally reported this issue a few weeks ago
(srry for no text wrapping):
https://lore.kernel.org/bpf/AyAj3bTqZ30lo9rs1fqBKO0Vk7CJqGfxcmHqHhmmEBpxlQxf0M4lfKOmSE_MbTVLhhxeFUx1PbyX6oZKq8Jh54h0pzjEFtXlRSqi4m6DcQA=@pm.me/
with the BPF global function name issue when freplace'ing a global func in
an ITER prog. I'm hoping for EXT to still support ITER progs for my
usecase, so rejecting all extensions seems extreme.
From what I understand, `tinfo` should be a registered iterator target
(`tgt_prog`/`prog->aux->dst_prog` in our case for an EXT prog),
and this is used to set `prog->aux->ctx_arg_info` for later verification.
Could `bpf_iter_prog_supported()` instead have the `tinfo` search loop be
applied on the `prog->aux->dst_prog`/`tgt_prog`, and
`bpf_prog_ctx_arg_info_init` on the original `prog`?
Ideally I'd still like EXT to support ITER prog types if possible.
Thanks.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH bpf-next v2 26/43] bpf: Don't take an extension for an iterator program
2026-10-17 22:06 [PATCH bpf-next v2 26/43] bpf: Don't take an extension for an iterator program Tyrone Wu
@ 2026-10-18 0:39 ` Alexei Starovoitov
0 siblings, 0 replies; 4+ messages in thread
From: Alexei Starovoitov @ 2026-10-18 0:39 UTC (permalink / raw)
To: Tyrone Wu; +Cc: andrii, bpf, daniel, eddyz87, josef, mason, memxor, netdev
On Sat, Oct 17, 2026 at 03:06 PM Tyrone Wu <tkwu@pm.me> wrote:
> Hi, I originally reported this issue a few weeks ago
Sorry, I missed that report. Both issues in there are real.
> I'm hoping for EXT to still support ITER progs for my
> usecase, so rejecting all extensions seems extreme.
It never worked though. As you found the load fails unless the func
is named bpf_iter_<target>, and then it's taken for the function of
that target. The patch only closes that hole.
> Could `bpf_iter_prog_supported()` instead have the `tinfo` search loop be
> applied on the `prog->aux->dst_prog`/`tgt_prog`, and
> `bpf_prog_ctx_arg_info_init` on the original `prog`?
That's a start, but not enough.
bpf_iter_get_func_proto() goes by attach_btf_id as well.
The iter link checks max_rdonly_access and max_rdwr_access of the iter prog
against the map. The extension has its own and nobody looks at them.
At the end it's a feature, not a fix.
Send a patch and please explain the use case.
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH bpf-next v2 00/43] bpf: Memory safety, lifetime and locking fixes
@ 2026-10-17 16:37 Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 26/43] bpf: Don't take an extension for an iterator program Alexei Starovoitov
0 siblings, 1 reply; 4+ messages in thread
From: Alexei Starovoitov @ 2026-10-17 16:37 UTC (permalink / raw)
To: bpf; +Cc: daniel, andrii, eddyz87, memxor, netdev, josef, mason
From: Alexei Starovoitov <ast@kernel.org>
This series collects fixes for bugs in the BPF core, the verifier and the
BPF side of the networking stack. Most of them are from Josef.
Every bug was reproduced in a VM on top of bpf-next, on the kernel right
before and right after the patch that fixes it. The splats are in the
commit logs. That goes for what the reviews of v1 have found as well.
Sleeping, or doing without RCU, where that is not allowed:
02 hash map for_each callbacks of sleepable programs
05 sleepable programs on the task_vma iterator
06 bpf_find_vma() callbacks of sleepable programs
24 maps that rely on RCU in bpf_wq and bpf_task_work callbacks
32 extensions of functions that run sleepable
Buffers that iterators and writable tracepoints hand to programs:
19 BPF_LINK_UPDATE skips the size check of the attach
25 tail calls from an iterator program
26 extensions of an iterator program
27 tail calls from a writable raw tracepoint program
28 extensions of a writable raw tracepoint program
29 writes over bpf_timer, bpf_spin_lock, kptr in a live map value
The sk_storage map iterator:
14 a socket that sk_clone() is still building can be found and used
15 NULL dereference if the socket goes away
16 an element of a storage that was never published can be found
17 the socket is not held while the program runs
Lifetime of local storage, programs and maps:
10 owner_refcnt saturates on the last unpin
30 map_free() frees elements under sleepable readers
31 values of a dead owner are freed under sleepable programs
22 a program is freed under its bpf_wq callback
23 an inner map is freed under a sleepable callback
33 the exception table of a program that still runs is not found
XDP and devices:
01 devmap egress programs free page_pool fragments as plain pages
20 stale offload->prog after bpf_prog_realloc()
21 a program is bound to a netdev that is being unregistered
35 cpumap uses the device of a queued frame after it is gone
seg6local End.BPF and bpf_skb_adjust_room():
11 the SRH of the inner packet is not validated after End.DT6
12 the inner header is not pulled for End.DT6
13 stale SRH pointer if End.B6 fails late
08 gso_size can drop to 0 or wrap around
skb dynptrs, where a write can reallocate the head of the skb:
36 kfuncs that write through a dynptr
37 bpf_dynptr_write() in a global function
38 a dynptr passed to a global function
39 extensions get the unclone prologue without an skb in R1
40 kfuncs that write through a dynptr do not unclone the skb
41 the source of the write is a slice of the same skb
42 overlapping source and destination
43 slices as arguments of helpers that change the packet
The rest:
03 inode leak if BPF_TOKEN_CREATE fails
04 preallocated hash map hands out an element that is still linked
07 BPF_JSET with a 64 bit mask, 32-bit kernels only
09 probe names of a perf event are read without event_mutex
18 unbounded recursion in the BTF show code
34 BPF_PROG_TEST_RUN of sk_lookup uses the socket outside of RCU
Some of the fixes make the kernel refuse what it has accepted so far:
- 02, 06: helpers, kfuncs and global functions that may sleep are rejected
in these callbacks.
- 05: sleepable programs cannot be attached to the task_vma iterator.
- 24: in sleepable callbacks, and for inner maps in sleepable programs,
maps that rely on RCU need bpf_rcu_read_lock().
- 25, 27: a program with a tail call cannot be attached to a map element
iterator or to a writable tracepoint.
- 29: an iterator program that writes over a special field cannot be
attached to that map.
- 36-38, 43: packet pointers and slices are invalidated in more places.
That hits some programs which are harmless at run time. A program that
keeps a packet pointer across a global function which only writes to a
ringbuf dynptr is one example.
- 04: a nested update of a preallocated hash map on the same CPU can fail
with -EBUSY.
- 08: bpf_skb_adjust_room() returns -ENOTSUPP if gso_size would drop below
TCP_MIN_GSO_SIZE.
- 28: writable raw tracepoint programs cannot be extended.
- 32: the main function of a sleepable program, and a global function that
is called without the RCU read lock, cannot be extended. The
summarization selftest is adjusted.
- 39: an extension that writes to packet data has to get the context as
its first argument, and scalars beside it.
test_progs in its three flavors, test_maps and test_verifier show no new
failures. cpumask/test_insert_leave is flaky when the tests run in
parallel, with and without the series: its program does not check
is_test_task(), so any other fork in the system makes it fail.
veristat sees no difference for the 5689 programs of the selftests, nor for
the 466 programs of the sched_ext schedulers that BPF CI builds: same
verdicts, insns, states and stack depth.
v1 -> v2, all of it after the reviews by sashiko and the BPF CI bot:
- rebased
- 04: cancel the special fields before the element goes into the slot
- 08: leave at least TCP_MIN_GSO_SIZE
- 16: new. The check in 17 did not hold for a storage that lost the race
in bpf_local_storage_alloc().
- 20: update offload->prog under bpf_devs_lock, in
bpf_jit_prog_release_other() as well
- 24: a global function that is called with preemption or interrupts
disabled got around the check
- 28, 32: new. Extensions got around 27 and 31.
- 31: leave the special fields to the RCU Tasks Trace callback too
- 39, 40: new. The kfuncs of 36 wrote to cloned skbs. 39 is needed for
40 not to give the prologue to extensions that cannot take it.
- 41: make the skb writable once
- 18: no change. bpf_snprintf_btf() and bpf_seq_printf_btf() only take
vmlinux BTF, and the map read in bpffs is BTF_SHOW_UNSAFE.
v1: https://lore.kernel.org/bpf/20261017012058.355787-1-alexei.starovoitov@gmail.com/
Alexei Starovoitov (6):
bpf: Clear sk_refcnt of a clone before its storage is linked
bpf: Link the first element after its storage is published
bpf: Don't take an extension for a writable raw tracepoint program
bpf: Don't take an extension for a function that runs sleepable
bpf: Refuse the prologue for an extension that cannot take it
bpf: Unclone the skb for kfuncs that write through a dynptr
Josef Bacik (37):
bpf: use the frame mem type in devmap egress XDP
bpf: forbid sleeping in hash map for_each callbacks
bpf: don't leak the inode when token creation fails
bpf: don't hand out a linked element as extra element
bpf: reject sleepable programs for task_vma iterator
bpf: forbid sleeping in bpf_find_vma() callbacks
bpf: look at all 64 bits of a BPF_JSET mask on 32-bit
bpf: don't let bpf_skb_adjust_room() use up the MSS
bpf: Read the probe of a perf event under event_mutex
bpf: Don't saturate owner_refcnt on the last unpin
bpf: Validate the SRH which End.DT6 uncovers in End.BPF
bpf: Pull the inner header for End.DT6 in End.BPF
bpf: Update the SRH state if End.B6 fails late
bpf: Fix NULL deref in the sk_storage map iterator
bpf: Hold the socket in the sk_storage map iterator
bpf: Bound the nesting that the BTF show code follows
bpf: Check the new program of an iterator link update
bpf: Fix stale offload->prog pointer after realloc
bpf: Don't bind a program to a netdev that goes away
bpf: Keep a program until its bpf_wq callback has ended
bpf: Count sleepable callbacks as sleepable map users
bpf: Check the maps that sleepable callbacks use
bpf: Assume no bounds for buffers behind a tail call
bpf: Don't take an extension for an iterator program
bpf: Assume no bounds for a writable tp with tail calls
bpf: Keep iterator programs off special map fields
bpf: Free what map_free() unlinks for sleepable readers
bpf: Keep values of a dead owner for sleepable programs
bpf: Keep the symbols of a program until it has ended
bpf: Use the socket of a sk_lookup test run under RCU
bpf, cpumap: Hold the device of frames in the queue
bpf: Drop packet pointers behind kfuncs writing an skb
bpf: Let bpf_dynptr_write() mark a global function
bpf: Don't take a dynptr argument for a local dynptr
bpf: Follow the head if an skb is written from a slice
bpf: Use memmove() to store bytes in an skb
bpf: Refuse packet slices for packet-changing helpers
include/linux/bpf.h | 43 ++-
include/linux/bpf_local_storage.h | 13 +
include/linux/bpf_verifier.h | 9 +
kernel/bpf/bpf_iter.c | 31 +-
kernel/bpf/bpf_local_storage.c | 50 +++-
kernel/bpf/btf.c | 14 +-
kernel/bpf/cfg.c | 4 +-
kernel/bpf/core.c | 56 ++--
kernel/bpf/cpumap.c | 35 ++-
kernel/bpf/devmap.c | 1 +
kernel/bpf/fixups.c | 30 ++
kernel/bpf/hashtab.c | 22 +-
kernel/bpf/helpers.c | 9 +-
kernel/bpf/map_in_map.c | 7 +-
kernel/bpf/map_iter.c | 79 +++--
kernel/bpf/offload.c | 25 +-
kernel/bpf/states.c | 3 +
kernel/bpf/syscall.c | 28 +-
kernel/bpf/task_iter.c | 12 +-
kernel/bpf/token.c | 5 +-
kernel/bpf/verifier.c | 269 +++++++++++++++---
kernel/trace/bpf_trace.c | 13 +
net/bpf/test_run.c | 19 +-
net/core/bpf_sk_storage.c | 96 ++++++-
net/core/filter.c | 58 +++-
net/core/sock_map.c | 17 +-
.../selftests/bpf/prog_tests/summarization.c | 21 +-
27 files changed, 781 insertions(+), 188 deletions(-)
base-commit: 458575e1f2ddea944d679fe778c92e370a9b61a4
--
2.55.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH bpf-next v2 26/43] bpf: Don't take an extension for an iterator program
2026-10-17 16:37 [PATCH bpf-next v2 00/43] bpf: Memory safety, lifetime and locking fixes Alexei Starovoitov
@ 2026-10-17 16:37 ` Alexei Starovoitov
2026-10-17 17:17 ` bot+bpf-ci
0 siblings, 1 reply; 4+ messages in thread
From: Alexei Starovoitov @ 2026-10-17 16:37 UTC (permalink / raw)
To: bpf; +Cc: daniel, andrii, eddyz87, memxor, netdev, josef, mason
From: Josef Bacik <josef@toxicpanda.com>
An extension inherits the expected_attach_type of the program it extends.
If that is BPF_TRACE_ITER, check_attach_btf_id() hands the extension to
bpf_iter_prog_supported(), which goes by the name of the attach function.
For an extension that is the name of the subprogram it replaces, so the
load fails with -EINVAL, unless that subprogram is called like the function
of a target, bpf_iter_bpf_map_elem for example.
Then the extension gets the context of that target. If the subprogram
has as many arguments, it can use the key and the value as buffers, but
how far it reaches is noted in the extension, where the test of the
iterator link does not look: it reads and writes behind the elements of
the map. And the id of the subprogram in the BTF of the program is cached
as the id of the target, so that programs of that target which are loaded
already cannot be attached.
Refuse all extensions here.
Fixes: 15d83c4d7cef ("bpf: Allow loading of a bpf_iter program")
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
---
kernel/bpf/bpf_iter.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/kernel/bpf/bpf_iter.c b/kernel/bpf/bpf_iter.c
index 4668c1696a08..5fd376bd210b 100644
--- a/kernel/bpf/bpf_iter.c
+++ b/kernel/bpf/bpf_iter.c
@@ -351,6 +351,13 @@ int bpf_iter_prog_supported(struct bpf_prog *prog)
const char *prefix = BPF_ITER_FUNC_PREFIX;
int prefix_len = strlen(prefix);
+ /*
+ * The attach function of an extension is a subprogram of the iterator
+ * program that it extends, whatever its name is.
+ */
+ if (prog->type == BPF_PROG_TYPE_EXT)
+ return -EINVAL;
+
if (strncmp(attach_fname, prefix, prefix_len))
return -EINVAL;
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH bpf-next v2 26/43] bpf: Don't take an extension for an iterator program
2026-10-17 16:37 ` [PATCH bpf-next v2 26/43] bpf: Don't take an extension for an iterator program Alexei Starovoitov
@ 2026-10-17 17:17 ` bot+bpf-ci
0 siblings, 0 replies; 4+ messages in thread
From: bot+bpf-ci @ 2026-10-17 17:17 UTC (permalink / raw)
To: alexei.starovoitov, bpf
Cc: daniel, andrii, eddyz87, memxor, netdev, josef, mason, ast,
andrii, daniel, martin.lau, eddyz87, yonghong.song, mason,
ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 3461 bytes --]
> bpf: Don't take an extension for an iterator program
TL;DR: The new EXT check in bpf_iter_prog_supported() may be incomplete: a
TRACING/BPF_TRACE_ITER program attached to a JITed program's function can
still reach it, possibly corrupting the iterator target's btf_id cache and
ctx_arg_info.
> diff --git a/kernel/bpf/bpf_iter.c b/kernel/bpf/bpf_iter.c
> index 4668c1696a08..5fd376bd210b 100644
> --- a/kernel/bpf/bpf_iter.c
> +++ b/kernel/bpf/bpf_iter.c
> @@ -351,6 +351,13 @@ int bpf_iter_prog_supported(struct bpf_prog *prog)
> const char *prefix = BPF_ITER_FUNC_PREFIX;
> int prefix_len = strlen(prefix);
>
> + /*
> + * The attach function of an extension is a subprogram of the iterator
> + * program that it extends, whatever its name is.
> + */
> + if (prog->type == BPF_PROG_TYPE_EXT)
> + return -EINVAL;
> +
> if (strncmp(attach_fname, prefix, prefix_len))
> return -EINVAL;
Is this check enough, or can the same problem be reached without an
extension?
A BPF_PROG_TYPE_TRACING program loaded with expected_attach_type set to
BPF_TRACE_ITER, attach_prog_fd pointing at a JITed program P1, and
attach_btf_id set to a global function of P1 named bpf_iter_bpf_map_elem
looks like it gets here too. bpf_prog_load_check_attach() has no
BPF_PROG_TYPE_TRACING case that rejects it, and in
bpf_check_attach_target() the BPF_TRACE_ITER case with tgt_prog set only
does:
btf_type_is_func() / func_proto checks
btf_distill_func_proto()
Unlike the BPF_TRACE_RAW_TP case just above it, it never rejects tgt_prog.
check_attach_btf_id() then stores the subprogram name of P1 in
prog->aux->attach_func_name and calls bpf_iter_prog_supported(). Since
prog->type is BPF_PROG_TYPE_TRACING here, the new check does not refuse it:
bpf_check()
check_attach_btf_id()
bpf_check_attach_target()
bpf_iter_prog_supported()
cache_btf_id()
tinfo->btf_id = prog->aux->attach_btf_id
The 'bpf_iter_' prefix matches and strcmp() against reg_info->target
matches, so cache_btf_id() caches an id from P1's BTF as the btf_id of the
target, and bpf_prog_ctx_arg_info_init() copies the target's ctx_arg_info.
This happens at check_attach_btf_id() time, so it persists even if the load
fails later.
After that, bpf_iter_link_attach() compares iter->btf_id with the poisoned
id, so already loaded programs of that target fail with -ENOENT. A vmlinux
BTF program whose attach_btf_id equals the forged id would be matched to the
wrong target (and the wrong ctx_arg_info) by the first branch of the loop in
bpf_iter_prog_supported().
The out-of-bounds buffer access described in the commit message does not
seem to apply to this route, since the program being attached is the one
whose max_rdonly_access is recorded. Only the btf_id cache corruption and
the ctx_arg_info mix-up remain. It needs CAP_BPF and CAP_PERFMON, the same
as the extension case.
Would it be better to refuse any program that has a dst_prog here, for
example:
if (prog->aux->dst_prog)
return -EINVAL;
That also covers all extensions, since they always have one. Alternatively,
could bpf_check_attach_target() reject tgt_prog for BPF_TRACE_ITER, as it
does for BPF_TRACE_RAW_TP?
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/39051545464
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-10-18 0:39 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-17 22:06 [PATCH bpf-next v2 26/43] bpf: Don't take an extension for an iterator program Tyrone Wu
2026-10-18 0:39 ` Alexei Starovoitov
-- strict thread matches above, loose matches on Subject: below --
2026-10-17 16:37 [PATCH bpf-next v2 00/43] bpf: Memory safety, lifetime and locking fixes Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 26/43] bpf: Don't take an extension for an iterator program Alexei Starovoitov
2026-10-17 17:17 ` bot+bpf-ci
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.