Commit Graph

1482152 Commits

Author SHA1 Message Date
Kumar Kartikeya Dwivedi
bfc888f045
bpf: Bound ownership depth through local kptrs and graph roots
Program-allocated objects can own other local objects through referenced
kptrs. bpf_obj_free_fields() follows those pointers through
__bpf_obj_drop_impl() synchronously, before the object storage is freed
through RCU. A self-referential local kptr type therefore permits arbitrarily
deep object chains, and dropping the head can exhaust the kernel stack.
Long acyclic type chains have the same problem.

btf_check_and_fixup_fields() still assumes referenced kptrs only point to
kernel types and checks ownership through list and rbtree roots only. Its
existing rule is sufficient for graph-only cycles: the target of each graph
edge must contain a node, so every type in a cycle has both a root and a
node. The rule rejects such a type owning another root, breaking every
cycle. It also limits graph-only chains to three types, or two if the first
type contains a node, and conservatively rejects longer acyclic chains.
The missing local-kptr edges, rather than a missed graph-only cycle, are the
bug introduced by support for bpf_kptr_xchg() into local kptrs.

Replace that restriction with one bounded ownership walk covering graph
roots and local referenced kptrs. Run it after all BTF records have been
fixed up, reject cycles and paths deeper than eight record-bearing types,
and cache each type's suffix depth while checking it against the remaining
budget. This also permits the longer acyclic graph-only layouts rejected
by the old rule; update their existing BTF tests accordingly.

Keep the bound independent of MAX_CALL_FRAMES because recursive destruction
can run below a BPF call chain. A plain local pointee without special-field
metadata adds only a final non-recursing drop. Non-owning kptrs and
kernel-BTF kptrs do not recurse through local records and remain outside the
walk. Include local percpu-kptr edges too, although allocation of percpu
objects with special fields is currently forbidden, so that relaxing that
restriction cannot bypass the ownership bound.

btf_check_and_fixup_fields() continues to initialize graph_root.value_rec,
including for separately allocated map records. The ownership relationships
belong to immutable program BTF and only need validation at BTF load time.

Fixes: b0966c7245 ("bpf: Support bpf_kptr_xchg into local kptr")
Reported-by: Nicholas Carlini <npc@anthropic.com>
Suggested-by: Nicholas Carlini <npc@anthropic.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20260914132444.2564218-2-memxor@gmail.com
2026-09-19 05:26:43 +00:00
Alexei Starovoitov
cdeea29719
Merge branch 'compare-stack-frames-in-exact-register-states'
Kumar Kartikeya Dwivedi says:

====================
Compare stack frames in exact register states

regs_exact() compares register values and their ID relationships, but it
does not compare frameno. regsafe() checks frameno for ordinary
PTR_TO_STACK comparisons, while its EXACT path returns through regs_exact()
before reaching that check. Infinite-loop detection can therefore mistake
pointers to the same offset in different stack frames for the same pointer
and reject a finite loop.

Move frameno into bpf_reg_state's type-specific metadata union so the
existing regs_exact() prefix comparison covers it. This avoids a separate
PTR_TO_STACK case and keeps the structure at 80 bytes. Adjust the
states_maybe_looping() comparison boundary for the new layout. Since
frameno now aliases other pointer metadata, bpf_func() returns NULL for
registers that are not stack pointers; the callers that look up the frame
before checking the register type dereference it only afterwards.

The selftest keeps a stack pointer live in a register across a loop
whose only change at the header is the pointer's frame number. On the
unfixed tree, the program is rejected with "infinite loop detected". With
the fix, it loads and returns the expected value.

Changelog:
----------
v3 -> v4
v3: https://lore.kernel.org/bpf/20260919004327.1403382-1-memxor@gmail.com

 * Return NULL from bpf_func() for non-stack registers, since frameno now
   aliases other pointer metadata and some callers look up the frame before
   checking the register type. (Sashiko)

v2 -> v3
v2: https://lore.kernel.org/bpf/20260918011313.3053497-1-memxor@gmail.com

 * Rebase on bpf/master.
 * Drop the redundant spilled-pointer test, since existing tests already
   cover the stacksafe() -> regsafe() path. (Eduard)
 * Place asm labels on their own line in the selftest. (Eduard)
 * Collect Acked-by and Tested-by tags.

v1 -> v2
v1: https://lore.kernel.org/bpf/20260914161340.3419141-1-memxor@gmail.com

 * Rebase on bpf/master.
 * Move frameno into the type-specific metadata union so regs_exact()'s
   existing prefix comparison covers it without growing bpf_reg_state.
====================

Link: https://patch.msgid.link/20260919014213.1840880-1-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-19 05:25:14 +00:00
Kumar Kartikeya Dwivedi
0705878489
selftests/bpf: Cover frame changes in bounded loops
Add a finite loop whose progress is represented only by changing the
frame number of a stack pointer. The loop first reads zero from the
caller's stack, switches to the same offset in the callee's stack, and
exits after reading one on its next iteration.

Force frequent checkpoints so the test exercises infinite-loop detection,
and check that the program returns one when run.

Without the frameno comparison in regs_exact(), the program is rejected
with an "infinite loop detected" diagnostic instead of loading
successfully.

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Tested-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260919014213.1840880-3-memxor@gmail.com
2026-09-19 05:25:14 +00:00
Kumar Kartikeya Dwivedi
8901cee931
bpf: Compare stack frames in regs_exact()
regs_exact() compares the register state up to id, followed by the ID
mappings, but does not compare frameno. The PTR_TO_STACK case in regsafe()
checks frameno separately, which is bypassed when exact comparison is
requested. Consequently, infinite-loop detection can treat pointers to
different stack frames as the same pointer and reject a finite loop.

For example, initialize fp-8 to zero in the caller and to one in the
callee, then pass the caller's fp-8 to the callee as r1:

    loop:
        r0 = *(u64 *)(r1 + 0);
        if r0 != 0 goto done;
        r1 = r10;
        r1 += -8;
        goto loop;
    done:
        exit;

The loop terminates after reading the callee's slot on its second
iteration. At the loop header, however, the only relevant difference is
r1's frameno, so exact comparison incorrectly reports an infinite loop.
The same problem occurs when the pointer is spilled to the stack.

Move frameno into the type-specific metadata union, ahead of id, so the
existing prefix comparison in regs_exact() covers it. Ordinary stack
pointers do not use another union member. Iterator and IRQ stack-slot
states use their dedicated union views and do not need a frame lookup.
This also keeps bpf_reg_state at 80 bytes.

Since frameno now shares storage with other pointer metadata, it is only
meaningful for PTR_TO_STACK registers. Return NULL from bpf_func() for
other register types. process_iter_arg(), get_constant_map_key() and
is_dynptr_reg_valid_init() look up the frame before checking the register
type and would otherwise index frame[] with a byte of the register's map
or BTF pointer. They dereference the frame only after their type check.

Move the states_maybe_looping() boundary from frameno to precise after the
field relocation. Its prefix comparison continues to cover the complete
value state and now includes frameno.

Continue to ignore precise. Precision marks control whether pruning may
ignore scalar ranges; they do not change the represented values, and exact
comparison already compares those ranges unconditionally. Marks can also
change through backtracking while an ancestor state is still being
explored.

Fixes: d5b892fd60 ("bpf: make infinite loop detection in is_state_visited() exact")
Reported-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260919014213.1840880-2-memxor@gmail.com
2026-09-19 05:25:14 +00:00
Kumar Kartikeya Dwivedi
b4e875d397 libbpf: Reject truncated ldimm64 CO-RE relocations
CO-RE relocation of an ldimm64 instruction operates on two instruction
slots. A malformed BPF ELF can end a function after the first slot and
attach a CO-RE relocation to it. libbpf allocates the instruction array
according to the function symbol size, so the shared relocation code would
then access beyond the allocation.

Reject a terminal ldimm64 in libbpf's relocation loop, where the program
length is available, before resolving or applying the relocation. Both
resolved and unresolved relocations validate the absent second slot, and
unresolved relocation poisoning would additionally write past the array.

The in-kernel caller is protected by the verifier's early instruction-stream
check before it applies CO-RE relocations.

Fixes: eacaaed784 ("libbpf: Implement enum value-based CO-RE relocations")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/20260914140852.03DA21F0089B@smtp.kernel.org
Link: https://patch.msgid.link/20260917233222.2542500-11-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
2026-09-17 18:01:43 -07:00
Kumar Kartikeya Dwivedi
04ae4ffc57 selftests/bpf: Check callback map value lock identity
Add a verifier test which retains a map value from an outer callback and
then acquires a lock through an inner callback value before attempting to
release the outer callback value. Both values can denote different elements,
so the verifier must reject the mismatched unlock.

Also exercise callbacks reached through two inner-map lookups. The lookup
results share inner_map_meta but may refer to different one-element arrays,
so their callback values must retain distinct lock identities.

Extend the existing spin_lock failure table and reuse its array and
inner-map fixtures to keep these cases alongside the other lock identity
tests. Update the nested callback reference-leak expectation for the extra
callback value ID.

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://patch.msgid.link/20260917233222.2542500-10-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
2026-09-17 18:01:43 -07:00
Kumar Kartikeya Dwivedi
71919742c8 bpf: Assign lock identity to callback map values
A nested bpf_for_each_map_elem() callback can unlock a different element
of the same map:

  static long inner(void *map, int *key, struct value *v,
                    struct value **outer_value)
  {
          bpf_spin_lock(&v->lock);
          bpf_spin_unlock(&(*outer_value)->lock);
          return 0;
  }

  static long outer(void *map, int *key, struct value *v, void *ctx)
  {
          bpf_for_each_map_elem(map, inner, &v, 0);
          return 0;
  }

Both callback values currently have ID zero and the same map_ptr.
process_spin_lock() compares those two fields, so it accepts the unlock
even though the two callbacks can receive different map elements.

Assign a fresh ID to every callback map value in the for-each,
timer/workqueue, and task-work constructors. Copies of one callback
argument retain its ID, so locking and unlocking through that argument
continues to work. Distinct callbacks also get distinct IDs for
single-element arrays, including inner arrays sharing inner_map_meta.

Preserve map_uid for every inner-map lookup and compare it through
check_ids() during state pruning. This preserves relationships between
maps, keys, and values while allowing equivalent states with different
lookup IDs to match. It avoids field-specific rules for when an inner map
needs an identity.

Move map_uid out of the metadata union and next to the other IDs, so
register comparisons can use the existing memcmp() ranges and remap the
IDs separately. Clear it when resetting a register or converting a map
lookup result to a socket pointer. Shrink frameno to u8, which is enough
for MAX_CALL_FRAMES, to make room without growing bpf_reg_state.

Fixes: d0d78c1df9 ("bpf: Allow locking bpf_spin_lock global variables")
Reported-by: Nicholas Carlini <npc@anthropic.com>
Suggested-by: Nicholas Carlini <npc@anthropic.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260917233222.2542500-9-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
2026-09-17 18:01:43 -07:00
Kumar Kartikeya Dwivedi
3440505aca selftests/bpf: Test CO-RE instruction poisoning restrictions
Add raw CO-RE relocations that fail to resolve their target enum value.
Place each supported and unsupported instruction form in dead code.
Unsupported targets must fail relocation with a diagnostic even when they
are unreachable. Supported ALU immediates, memory accesses, and ldimm64
instructions must still be poisoned and removed as dead code, allowing the
program to load. Check that both halves of ldimm64 are poisoned.

Load every instruction stream without relocations first to ensure that
rejection is caused by the relocation rather than the original program.

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260917233222.2542500-8-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
2026-09-17 18:01:43 -07:00
Kumar Kartikeya Dwivedi
394ae39833 bpf: Restrict CO-RE poisoning to relocatable instructions
CO-RE relocation records can name any instruction offset. When a
relocation cannot be resolved, bpf_core_patch_insn() currently poisons its
target before checking whether that instruction is a valid relocation
target. Malformed metadata can therefore replace jumps, calls, exits,
register-source arithmetic, or non-immediate loads instead of failing at
the relocation step.

Handle poisoning only after the instruction has passed the same class and
operand-form checks used for a resolved relocation. Route invalid forms
through the existing diagnostic and return a hard error. Keep poisoning
supported instructions, including both halves of a plain ldimm64, so an
unresolved relocation in dead code remains valid.

Extend bpf_core_poison_insn() to poison both halves of ldimm64, and return
its status directly from each validated instruction case. This avoids
routing the success path through a common label and leaves the helper free
to report errors.

The shared relocation code applies this restriction to both libbpf and
in-kernel CO-RE.

Fixes: d7a252708d ("libbpf: Improve handling of failed CO-RE relocations")
Reported-by: Nicholas Carlini <npc@anthropic.com>
Suggested-by: Nicholas Carlini <npc@anthropic.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260917233222.2542500-7-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
2026-09-17 18:01:42 -07:00
Kumar Kartikeya Dwivedi
968ee7c06b selftests/bpf: Test early in-kernel CO-RE relocation
Add a raw program load with CO-RE relocation metadata but no func_info or
line_info. Place the relocation in dead code and require the poisoning log,
proving that the kernel processes standalone CO-RE metadata instead of
silently skipping it.

Also give a subprogram a relocatable immediate as its terminal instruction.
Require the relocation's poisoning log before check_subprogs() rejects the
resulting fall-through. With the old ordering, check_subprogs() rejects the
original terminal instruction before CO-RE can emit the substitution log, so
the test continues to distinguish the ordering after relocation target
validation is tightened.

Submit a trailing ldimm64 first slot with CO-RE metadata and require the early
structural diagnostic. This exercises the check that protects relocation
processing instead of the later regular instruction validation.

Load the standalone instruction stream without relocation metadata first to
ensure that CO-RE processing causes its poisoning diagnostic. Encode the fixed
BTF metadata directly with the selftest BTF helpers.

Suggested-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260917233222.2542500-6-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
2026-09-17 18:01:42 -07:00
Kumar Kartikeya Dwivedi
c26e97721b bpf: Apply CO-RE relocations before subprogram validation
check_subprogs() verifies that each subprogram ends in an exit or an
unconditional jump before in-kernel CO-RE relocations are applied. An
unresolved relocation can then replace that terminal instruction with an
invalid helper call. The resulting fall-through into another subprogram
breaks the CFG invariant used by postorder and stack liveness analysis,
which can write past their per-subprogram arrays.

Apply CO-RE relocations immediately after preparing the program BTF, before
subprogram discovery and validation. Keep func_info and line_info validation
after subprogram discovery because those records depend on the complete
subprogram layout.

Reject an ldimm64 first slot at the end of the instruction stream before
CO-RE can inspect its missing second slot. check_subprogs() previously
rejected this form before relocation processing because it is not a valid
subprogram terminator. Moving CO-RE ahead of check_subprogs() removes that
implicit protection, so perform an explicit check before applying
relocations.

Include core_relo_cnt when deciding whether to prepare program BTF. A load
that supplied only CO-RE relocation metadata previously skipped both BTF
setup and relocation processing.

Fixes: fbd94c7afc ("bpf: Pass a set of bpf_core_relo-s to prog_load command.")
Suggested-by: Andrii Nakryiko <andrii@kernel.org>
Suggested-by: Alexei Starovoitov <ast@kernel.org>
Suggested-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260917233222.2542500-5-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
2026-09-17 18:01:42 -07:00
Kumar Kartikeya Dwivedi
2059d9af54 selftests/bpf: Test packet pointer class displacement pruning
Add two paths whose packet pointer ranges are individually compatible at
a join but whose members have different relative displacements. The first
path proves an eight-byte access through one member. On the second path,
the same guard only proves that the access starts before data_end.

An affected verifier prunes the second path and accepts the program. With
packet pointer class displacement preserved, it explores that path and
rejects the out-of-bounds access.

Read the unknown offset and branch selector directly from XDP context
fields, and force state checkpoints so the pruning attempt does not
depend on the verifier checkpoint heuristics.

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://patch.msgid.link/20260917233222.2542500-4-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
2026-09-17 18:01:42 -07:00
Kumar Kartikeya Dwivedi
fd16449a9b bpf: Preserve packet pointer class displacement in regsafe()
regsafe() maps packet pointer IDs between states and checks that each
current register range is a subset of the corresponding explored
register range. It does not, however, preserve the displacement between
registers that share a packet pointer ID.

This is unsound because packet range is shared by ID. A bounds check on
one class member updates every member, and a later access can consume the
range through another member. Commit 022ac07508 ("bpf: use reg->var_off
instead of reg->off for pointers") folded the fixed pointer offset into
r64 and removed the old off equality check, so two individually narrower
registers can prune even when their displacement has changed. The
explored path can then license an out-of-bounds packet access on the
pruned path.

Require matching range bases for packet pointers with an ID. Together
with the existing ID mapping, this preserves the displacement between
members of each packet-pointer class without adding per-ID state.
Packet pointers without an ID remain unaffected.

Fixes: 022ac07508 ("bpf: use reg->var_off instead of reg->off for pointers")
Reported-by: Nicholas Carlini <npc@anthropic.com>
Suggested-by: Nicholas Carlini <npc@anthropic.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260917233222.2542500-3-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
2026-09-17 18:01:42 -07:00
Kumar Kartikeya Dwivedi
261b61d373 bpf: Make post-verification instruction rewrites killable
After do_check() returns, the verifier runs several instruction rewrite
passes. Some of them patch or remove one instruction at a time. Each
operation moves the remaining instruction and auxiliary-data arrays and
adjusts all branch offsets, making the overall work quadratic in the
program length.

A privileged loader can submit 131072 unconditional jumps by zero followed
by a valid return. Verification finishes quickly, but bpf_opt_remove_nops()
then spends a long time removing each jump separately. Since this
post-verification work neither checks for signals nor reschedules, a pending
SIGKILL cannot terminate the task until the rewrite finishes.

Make bpf_patch_insn_data() and verifier_remove_insns() common cancellation
and rescheduling points. These helpers run from BPF_PROG_LOAD process
context, and bpf_patch_insn_data() can already sleep while reallocating
auxiliary data.

Report interrupted constant blinding as -EINTR and propagate it through
both JIT paths, including kernels that permit interpreter fallback.
Other blinding failures retain the existing fallback behavior.

This does not reduce the quadratic cost of the rewrite passes, but it makes
the work preemptible and allows a killed loader to be torn down promptly.

Fixes: 52875a04f4 ("bpf: verifier: remove dead code")
Reported-by: Nicholas Carlini <npc@anthropic.com>
Suggested-by: Nicholas Carlini <npc@anthropic.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260917233222.2542500-2-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
2026-09-17 18:01:42 -07:00
Weiming Shi
50e80e2bb5 bpf: Skip unsettled links in link iterator
bpf_link_prime() inserts a link into link_idr before anon_inode_getfile()
succeeds and before bpf_link_settle() publishes the ID in link->id.
bpf_link_by_id() treats such an ID-zero link as unsettled, but the link
iterator takes a reference without this check.

If anon_inode_getfile() then fails, the creator removes the ID and frees
its still-private link directly.  The iterator is left with a dangling
reference and its next bpf_link_put() accesses freed memory.

Treat ID-zero entries as transient in bpf_link_get_curr_or_next(), just as
bpf_link_by_id() does.

  BUG: KASAN: slab-use-after-free in bpf_link_put
  Write of size 8 by task exp/384
  Call Trace:
  bpf_link_put                    kernel/bpf/syscall.c:3372
  bpf_link_seq_next               kernel/bpf/link_iter.c:33
  bpf_seq_read                    kernel/bpf/bpf_iter.c:158
  vfs_read                        fs/read_write.c:572
  ksys_read                       fs/read_write.c:716
  do_syscall_64                   arch/x86/entry/syscall_64.c:84
  entry_SYSCALL_64_after_hwframe  arch/x86/entry/entry_64.S:121
  Kernel panic - not syncing: KASAN: panic_on_warn set ...

Fixes: 9f88361273 ("bpf: Add bpf_link iterator")
Reported-by: Xiang Mei <xmei5@asu.edu>
Signed-off-by: Weiming Shi <bestswngs@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20260914170206.170723-2-bestswngs@gmail.com
2026-09-17 15:00:17 -07:00
Zhiling Zou
70504de0bb xsk: Use a 32-bit compare in xsk_map_gen_lookup
xsk_map_gen_lookup() loads a u32 key and compares it with max_entries
using BPF_JMP_IMM. BPF immediates are sign-extended to 64 bits, so a
max_entries value of 0x80000000 or higher becomes a threshold larger
than every zero-extended 32-bit key. An out-of-range index then skips
the bounds check and the generated lookup reads past xsk_map[].

Compare with BPF_JMP32_IMM so the check stays in 32-bit unsigned range.

Fixes: e65650f291 ("bpf: Implement map_gen_lookup() callback for XSKMAP")
Reported-by: Vega <vega@nebusec.ai>
Signed-off-by: Zhiling Zou <zhilinz@nebusec.ai>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Link: https://patch.msgid.link/7d2cb8e8dfaa9eb8fdff85156987a60960787dc3.1789056660.git.zhilinz@nebusec.ai
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
2026-09-17 10:56:16 -07:00
Eduard Zingerman
9e4188d7a4 Merge branch 'fix-global-subprog-verification-context'
Kumar Kartikeya Dwivedi says:

====================
Fix global subprog verification context

Global subprogs can be invoked in both sleepable and non-sleepable
contexts, but are verified based on context assumptions for the program
type as a whole and not the precise context in which they are invoked.
Nicholas identified that this can violate verifier safety assumptions.
Verify global subprogs once for each observed sleepability context and add
workqueue callback regression tests.

Changelog:
----------
v2 -> v3
v2: https://lore.kernel.org/bpf/20260905051224.2325381-1-memxor@gmail.com

 * Clarify that globals are checked only in contexts from which they are
   reached, with two passes only when both contexts occur. (Alexei)
 * Implement in_sleepable_context() as !in_rcu_cs(). (Alexei, Eduard)
 * Keep the original subprogram traversal order and repeat until all
   called contexts have been verified. (Eduard)
 * Explain why instruction accounting needs the saved total and why the
   exception callback uses the main program's context. (Eduard)
 * Rename the do_check_common() parameter to is_sleepable. (BPF CI)
 * Preserve the harmless global calls with __weak __noinline and check
   their instruction totals across both contexts. Drop the redundant
   task-work global RCU test and retain the review acknowledgment. (Eduard)

v1 -> v2
v1: https://lore.kernel.org/bpf/20260905034018.2095649-1-memxor@gmail.com

 * Preserve the harmless global subprog calls in the positive test with
   barrier() so LLVM cannot eliminate the intended coverage.
 * Return zero explicitly from workqueue callbacks after global subprog calls.
 * Document cumulative instruction accounting across verification contexts.
 * Fix BPF multi-line comment formatting.
====================

Link: https://patch.msgid.link/20260914131923.2544250-1-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
2026-09-17 10:56:08 -07:00
Kumar Kartikeya Dwivedi
a452e729b7 selftests/bpf: Test global subprog callback contexts
Exercise global subprogram verification from workqueue callbacks, which
can run in a sleepable context even when the containing program is not
sleepable. An unprotected callback must not let the global subprogram use
implicit RCU protection inherited from the program.

Add a negative case which loads an RCU-protected task kptr in a global
subprogram reached from a workqueue callback. It fails on an unfixed
kernel because the program is incorrectly accepted. Also cover a
workqueue callback protected by an explicit RCU read-side critical
section, where the same global subprogram remains valid.

Call the same harmless global subprogram directly from the main program
and from an unprotected callback. Mark it __weak __noinline so both calls
survive optimization, and check that its instruction statistics account
for both verification contexts. This also verifies that global calls
from callbacks are not rejected wholesale. Workqueue callbacks return
zero explicitly after the global call, as required by their contract.

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260914131923.2544250-3-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
2026-09-17 10:55:55 -07:00
Kumar Kartikeya Dwivedi
40c2096961 bpf: Verify global subprogs in each sleepability context
Global subprograms are verified independently with a fresh verifier root.
do_check_common() currently seeds that root's in_sleepable state from the
program, even though a global subprogram can also run from callbacks whose
execution context differs from the program's main entry point.

In particular, workqueue and task-work callbacks are sleepable even when
the containing program is not. A global subprogram of that program is
therefore verified as non-sleepable, making in_rcu_cs() true and allowing
loads of RCU-protected kptrs to produce trusted MEM_RCU pointers. The same
subprogram can then be called from a sleepable callback without a classic
RCU reader. It can retain such a pointer while the object is freed and use
it after free.

The verifier's execution-context predicates are complementary. A state is
sleepable only when in_sleepable is set and no RCU, preemption, IRQ, or lock
region is active. Each condition which prevents sleeping also provides RCU
protection, while in_rcu_cs() treats a non-sleepable state as implicitly
protected.

Use this relationship to represent a global subprogram caller with only the
result of in_sleepable_context(). A protected sleepable caller is normalized
to in_sleepable=false at the independent verification root. This both
prevents sleepable operations and makes in_rcu_cs() true without copying
caller-owned lock state.

Track only the contexts in which each global subprogram is actually
reached. Verify it once if all reachable calls use the same context, and
twice only if both sleepable and non-sleepable calls reach it. Calls found
while verifying globals or asynchronous callbacks mark further contexts
for checking. Repeat the existing subprogram walk until all called
contexts have been verified; unreachable global calls remain unchecked.

Accumulate instruction counts over those verification passes. Preserve
the total recorded before each pass, since path accounting has already
added this pass's synchronous instructions and its root total must also
include asynchronous subprograms.

This makes an unprotected callback verify the global subprogram as
sleepable, turning its RCU-protected kptr load into an untrusted pointer.
Protected callers and global subprograms which do not depend on implicit RCU
protection remain valid.

Fixes: 81f1d7a583 ("bpf: wq: add bpf_wq_set_callback_impl")
Fixes: 38aa7003e3 ("bpf: task work scheduling kfuncs")
Reported-by: Nicholas Carlini <npc@anthropic.com>
Suggested-by: Nicholas Carlini <npc@anthropic.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260914131923.2544250-2-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
2026-09-17 10:55:21 -07:00
Alexei Starovoitov
ee363e0558 Merge branch 'bpf-arm64-fix-the-exception-callback-s-frame-pointer'
Donggeun Yoo says:

====================
bpf, arm64: fix the exception callback's frame pointer

The arm64 JIT does not set BPF_REG_FP in the prologue of an exception
callback, so the callback runs with whatever x25 held when bpf_throw()
was called. A callback that materializes the register, for instance to
pass the address of a local variable to a helper, then works on the
frame of the subprogram that threw.

Patch 1 sets ctx->fp_used on that path, the same fix commit b114fcee76
("bpf, arm64: Fix fp initialization for exception boundary") made for
the exception boundary. Patch 2 adds a selftest that reaches the case.

Tested on aarch64 under QEMU with vmtest.sh, on the base below. Without
patch 1 the new test panics the kernel, because the address handed to
the helper lands on the helper's own saved return address:

  pc : 0x1234
  lr : 0x1234
  Call trace:
   0x1234 (P)
   bpf_test_run+0x188/0x3e0
   bpf_prog_test_run_skb+0x47c/0x998
   __sys_bpf+0xbdc/0xdd8
  Kernel panic - not syncing: Oops: Fatal exception in interrupt

0x1234 is the value the callback reads, so the helper wrote it over its
own return address. With patch 1 applied the whole group passes:

  #117/11  exceptions/exception_throw_subprog_stack_cb:OK
  #117     exceptions:OK
  Summary: 1/118 PASSED, 0 SKIPPED, 0/0 FAILED

Not tested on other architectures.

v1: https://lore.kernel.org/bpf/20260904070210.4163193-1-donggeunyoo.kernel@gmail.com/
v2: https://lore.kernel.org/bpf/20260907054235.473103-1-donggeunyoo.kernel@gmail.com/

v2 -> v3:
 - patch 2: use the standard multi-line comment style
 - patch 1: no change, added the Acked-by

Nothing compiled changed, so the numbers above are still v2's.

v1 -> v2:
 - rebase onto bpf/master; CI could not apply v1
 - spell the three new declarations u64 rather than __u64, to match the
   rest of progs/exceptions.c
 - no change to patch 1
====================

Link: https://patch.msgid.link/20260907130624.611942-1-donggeunyoo.kernel@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-13 21:59:21 -07:00
Donggeun Yoo
26a43a5f8c selftests/bpf: cover the exception callback using its own BPF stack
The existing exception tests do not reach a callback that materializes
BPF_REG_FP into a register. They either throw from the main program,
where BPF_REG_FP already holds the value the callback needs, or use a
callback whose only stack accesses are frame pointer relative, which the
arm64 JIT rewrites to be stack pointer relative.

Add a test that throws from a subprogram using its own BPF stack, with a
callback that hands the address of a local variable to
bpf_probe_read_kernel(). The helper and the callback have to name the
same slot for the value read back to be the one the helper stored.

Signed-off-by: Donggeun Yoo <donggeunyoo.kernel@gmail.com>
Link: https://lore.kernel.org/r/20260907130624.611942-3-donggeunyoo.kernel@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-13 21:59:21 -07:00
Donggeun Yoo
ef1fb82f12 bpf, arm64: set up the frame pointer for the exception callback
A program acting as exception boundary saves all callee-saved registers,
so build_prologue() takes the exception_cb path and never calls
push_callee_regs(). That is the only place find_used_callee_regs() runs,
and with it the only place ctx->fp_used is set, so the callback prologue
does not emit the

  mov x25, sp

that points BPF_REG_FP at the frame the callback runs on. x25 keeps
whatever it held when bpf_throw() was called. If the throw came from a
subprogram that uses its own BPF stack, that is the subprogram's frame
pointer, and since the subprogram never returns it never restores x25
either.

Stack accesses through BPF_REG_FP are rewritten to be stack pointer
relative, so those still land in the callback's own frame. Materializing
the register does not: a callback that passes the address of a local
variable to a helper hands over an address in the dead subprogram's
frame. That address is below the callback's stack pointer by then, and
the helper's own call chain covers it, so the helper can write over its
own return address. 0x1234 below is the value the helper was asked to
store:

  pc : 0x1234
  lr : 0x1234
  Call trace:
   0x1234 (P)
   bpf_test_run+0x188/0x3e0
   bpf_prog_test_run_skb+0x47c/0x998
   __sys_bpf+0xbdc/0xdd8
  Kernel panic - not syncing: Oops: Fatal exception in interrupt

Set ctx->fp_used on the exception callback path so that the existing code
further down sets x25 from the stack pointer. The epilogue restores it
from the main program's save area along with the other callee-saved
registers, as it already does. x86 sets the frame pointer for the
callback from the argument it is passed, and powerpc computes it from
the stack pointer.

Fixes: 5d4fa9ec56 ("bpf, arm64: Avoid blindly saving/restoring all callee-saved registers")
Acked-by: Xu Kuohai <xukuohai@huawei.com>
Signed-off-by: Donggeun Yoo <donggeunyoo.kernel@gmail.com>
Link: https://lore.kernel.org/r/20260907130624.611942-2-donggeunyoo.kernel@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-13 21:59:21 -07:00
Masoud Aghasi
953824e508 bpf: Fix u32 overflow issue in map batch operations
Several map batch operation implementations such as
generic_map_lookup_batch() use calculations in the form of
"values + cp * map->value_size" to compute the desired userspace memory
address for reading or writing. This can overflow the u32 type
(the result of "cp * map->value_size") when the map size exceeds 4GB.

generic_map_lookup_batch() may corrupt values for some keys in
userspace memory, and in some cases it mismatches values for some keys
while still reporting success.

Other batch operations may fail to delete or update some keys,
or the syscall may return unexpected errors.

Add size_t casts to prevent the affected offset and size calculations
from overflowing.

Fixes: cb4d03ab49 ("bpf: Add generic support for lookup batch op")
Fixes: aa2e93b8e5 ("bpf: Add generic support for update and delete batch ops")
Fixes: 057996380a ("bpf: Add batch ops to all htab bpf map")
Signed-off-by: Masoud Aghasi <maghasi@disroot.org>
Link: https://lore.kernel.org/r/20260903082734.623904-1-maghasi@disroot.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-13 21:58:40 -07:00
Geliang Tang
490a83d638 bpf, sockmap: Fix self-redirect copied_seq double-counting
When a BPF stream_verdict program redirects an skb back to the same
socket (self-redirect with BPF_F_INGRESS), sk_psock_verdict_apply()
calls tcp_eat_skb() which advances tcp_sk->copied_seq. However, the
skb is then delivered to the socket's psock ingress queue and later
read by tcp_bpf_recvmsg_parser(), which also advances copied_seq via
the copied_from_self accounting path. This double-counting causes
copied_seq to advance by 2x the actual data length, triggering:

  TCP recvmsg seq # bug 2: copied BF2E806, seq BF2E7FD, \
			   rcvnxt BF2E806, fl 0
  WARNING: net/ipv4/tcp.c:2745 at tcp_recvmsg_locked+0x72b/0x2640
  Call Trace:
   tcp_recvmsg+0x10a/0x500
   sock_recvmsg+0x168/0x1d0
   __sys_recvfrom+0x19a/0x2a0
   __x64_sys_recvfrom+0xe4/0x1f0
   do_syscall_64+0xf7/0x530
   entry_SYSCALL_64_after_hwframe+0x77/0x7f

  cleanup rbuf bug: copied BF2E806 seq BF2E806 rcvnxt BF2E806
  WARNING: net/ipv4/tcp.c:1609 at tcp_cleanup_rbuf+0xf2/0x1c0
  Call Trace:
   tcp_recvmsg_locked+0x8d1/0x2640
   tcp_recvmsg+0x10a/0x500
   sock_recvmsg+0x168/0x1d0
   __sys_recvfrom+0x19a/0x2a0
   __x64_sys_recvfrom+0xe4/0x1f0
   do_syscall_64+0xf7/0x530
   entry_SYSCALL_64_after_hwframe+0x77/0x7f

Fix this by converting self-redirect verdict to __SK_PASS at the
beginning of sk_psock_verdict_apply(). This bypasses the
__SK_REDIRECT case entirely (which calls sk_psock_eat_skb), letting
the __SK_PASS path queue the skb to the psock ingress queue. The
data is then read via tcp_bpf_recvmsg_parser(), which advances
copied_seq exactly once through copied_from_self. Cross-socket
redirects continue through __SK_REDIRECT with sk_psock_eat_skb()
unchanged.

Fixes: e5c6de5fa0 ("bpf, sockmap: Incorrectly handling copied_seq")
Suggested-by: Jakub Sitnicki <jakub@cloudflare.com>
Suggested-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Link: https://lore.kernel.org/r/1a8e797a1b26e2f695aaac22ac644c2862f63466.1788858299.git.tanggeliang@kylinos.cn
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-13 21:50:26 -07:00
Pu Lehui
1c21452d02 bpf: Fix UAF due to concurrent consumption of ttrace lists in alloc_bulk
Syzkaller repeatedly triggered UAF splats related to nodes in
waiting_for_gp_ttrace within the bpf memalloc:

BUG: KASAN: slab-use-after-free in llist_del_first+0x85/0x110 lib/llist.c:61
Read of size 8 at addr ffff8881572cd080 by task syz.4.470/5112
 ...
 llist_del_first+0x85/0x110 lib/llist.c:61
 alloc_bulk+0x193/0x460 kernel/bpf/memalloc.c:229
 bpf_mem_refill+0x386/0x560 kernel/bpf/memalloc.c:436

Freed by task 14:
 ...
 __free_rcu kernel/bpf/memalloc.c:281 [inline]
 __free_rcu_tasks_trace+0x48/0xd0 kernel/bpf/memalloc.c:291
 rcu_tasks_invoke_cbs+0x1ec/0x3e0 kernel/rcu/tasks.h:571
 rcu_tasks_one_gp+0x13d/0x220 kernel/rcu/tasks.h:621
 rcu_tasks_kthread+0xf3/0x120 kernel/rcu/tasks.h:651

The reason is that the UAF occurs after the RCU Tasks Trace GP expires:
when the __free_rcu() callback runs, there is no synchronization
protecting llist_del_all() against concurrent alloc_bulk() operating on
waiting_for_gp_ttrace, leading to the race condition below:

CPU0                                           CPU1
                                               __free_rcu (RCU Tasks Trace callback)
alloc_bulk
  llist_del_first(&c->waiting_for_gp_ttrace)
    entry = smp_load_acquire(&head->first);
    do {
      if (entry == NULL)
        return NULL;
                                               free_all(llist_del_all(&c->waiting_for_gp_ttrace))
                                                 llist_for_each_safe(pos, t, llnode)
                                                   free_one(pos);
      next = READ_ONCE(entry->next); <-- trigger UAF
    } while (!try_cmpxchg(&head->first, &entry, next));

In addition, there is also a theoretical race condition on the
free_by_rcu_ttrace list. This race requires two preconditions: an
in-flight Tasks Trace GP keeping c->call_rcu_ttrace_in_progress == 1,
and concurrent cross-CPU frees repopulating c->free_by_rcu_ttrace with
new nodes. Under these conditions, the following scenario triggers UAF:

// CPU0
// irq work is still busy (on PREEMPT_RT)
alloc_bulk()
  llist_del_first(&c->free_by_rcu_ttrace)
    entry = smp_load_acquire(&head->first);
    do {
      if (entry == NULL)
        return NULL;

        // CPU1
        bpf_mem_alloc_destroy()
          WRITE_ONCE(c->draining, true)
          // wait for CPU0
          irq_work_sync()

                // CPU2
                do_call_rcu_ttrace(tgt(CPU0))
                  if (c->draining) {
                    llist_del_all(&c->free_by_rcu_ttrace)
                    free_all()
                  }

// CPU0 continue
      next = READ_ONCE(entry->next); <-- trigger UAF
    while (!try_cmpxchg(&head->first, &entry, next));

Fix this by introducing a raw spinlock to synchronize the concurrent
consumption on waiting_for_gp_ttrace and free_by_rcu_ttrace.

Fixes: 04fabf00b4 ("bpf: Allow reuse from waiting_for_gp_ttrace list.")
Suggested-by: Alexei Starovoitov <ast@kernel.org>
Suggested-by: Hou Tao <houtao1@huawei.com>
Signed-off-by: Pu Lehui <pulehui@huawei.com>
Acked-by: Hou Tao <houtao1@huawei.com>
Link: https://lore.kernel.org/r/20260905021139.4116529-1-pulehui@huaweicloud.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-13 19:37:20 -07:00
Zhixing Chen
7d70a0b02d bpf: Use kvfree() in xdp_test_run_teardown()
xdp_test_run_setup() allocates xdp->frames and xdp->skbs with
kvmalloc_array(). The setup error path already releases both arrays with
kvfree(), while the normal teardown path still uses kfree().

Use kvfree() in xdp_test_run_teardown() as well, so the release helper
matches the allocator on both paths.

Signed-off-by: Zhixing Chen <running910@gmail.com>
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Link: https://lore.kernel.org/r/20260903104358.29228-1-running910@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-12 12:11:41 -07:00
Jiayuan Chen
75f8cf2246 bpf: Fix out-of-bounds read of rtt_min in sock_ops
A sockops prog reading skops->rtt_min never checks the sk type: on the
tcp_conn_request() path sock_ops->sk is a request_sock (non-full), and the
ctx rewrite casts it to a tcp_sock (full) and reads rtt_min past the end of
the request_sock, returning dirty adjacent memory.

	SEC("sockops")
	int prog(struct bpf_sock_ops *skops)
	{
		switch (skops->op) {
		case BPF_SOCK_OPS_RWND_INIT:
			leak = skops->rtt_min;   /* reads the request_sock OOB */
		...
		}
	}

For instance one such read returned rtt_min=0xffff8881, the high half of a
leaked kernel pointer.

Guarding that cast is exactly what SOCK_OPS_GET_FIELD() does -- it checks
is_locked_tcp_sock and returns 0 when sock_ops->sk is not a locked full
socket. Every other tcp_sock field in sock_ops goes through it; rtt_min is
the only one open-coded, so it skips the check.

Read rtt_min through SOCK_OPS_GET_FIELD() too. rtt_min is a bit special:
it is a struct minmax and we only want the current min, so pass
rtt_min.s[0].v. That is equivalent to the old hand-computed offset

	offsetof(struct tcp_sock, rtt_min) + sizeof_field(struct minmax_sample, t)

(s[0] sits at rtt_min + 0 and .v at + sizeof(.t), i.e. what minmax_get()
returns), so the loaded field is unchanged and only the full-sock guard is
added. The two BUILD_BUG_ON()s that protected the hand-computed offset
are no longer needed.

Before patch:

	0: r1 = *(u64 *)(r1 +0)      ; r1 = skops->sk
	1: r1 = *(u32 *)(r1 +2324)   ; ((tcp_sock *)sk)->rtt_min.s[0].v

After patch:

	0: *(u64 *)(r1 +56) = r9
	1: r9 = *(u8 *)(r1 +50)      ; is_locked_tcp_sock
	2: if r9 == 0 goto pc+4      ; not a locked full sock -> 0
	3: r9 = *(u64 *)(r1 +56)
	4: r1 = *(u64 *)(r1 +0)      ; r1 = skops->sk
	5: r1 = *(u32 *)(r1 +2324)   ; rtt_min.s[0].v
	6: goto pc+2
	7: r9 = *(u64 *)(r1 +56)
	8: r1 = 0

Fixes: 44f0e43037 ("bpf: Add support for reading sk_state and more")
Reported-by: VEGA <vega@nebusec.ai>
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Link: https://lore.kernel.org/r/20260903100921.113374-1-jiayuan.chen@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-12 11:11:10 -07:00
Jose Fernandez (Anthropic)
85136bf224 bpf: Avoid soft lockup in __htab_map_lookup_and_delete_batch()
__htab_map_lookup_and_delete_batch() has no rescheduling point. The
batch count bounds how many entries are copied out, not how many
buckets are visited, so one BPF_MAP_LOOKUP_BATCH call can walk the
map end to end. The empty-bucket fast path is worse: it stays inside
a single rcu_read_lock() / bpf_disable_instrumentation() section for
any run of consecutive empty buckets.

That holds up on small maps, but it falls apart at scale. On a
144-CPU arm64 host running a CONFIG_PREEMPT_NONE kernel, periodic
BPF_MAP_LOOKUP_BATCH calls against an LRU hash map with 16,777,216
buckets held a CPU inside the batch op for 77+ seconds and triggered
the soft lockup watchdog.

Commit 75134f16e7 ("bpf: Add schedule points in batch ops") fixed this
same problem in the generic batch ops, but not in this htab-native path,
which every htab-based hash map variant uses for its lookup[_and_delete]
batch ops.

Complete that fix here. Leave the critical section after 64 consecutive
empty buckets, call cond_resched_tasks_rcu_qs(), and resume at the saved
bucket cursor. No locks are held at that point, and resuming from the
cursor is already the function's behavior for non-empty buckets. Add the
same call to the per-bucket loop after copy_to_user(), where every lock
has been dropped. cond_resched_rcu() is not enough here: sleeping with
bpf_prog_active elevated makes tracing programs on that CPU silently
skip their invocations.

Plain cond_resched() is not enough either. It is a no-op under PREEMPT
and PREEMPT_LAZY, the only models arm64 and x86 have offered since
commit 7dadeaa6e8 ("sched: Further restrict the preemption modes").
It is also never a Tasks RCU quiescent state, in any model: the
reschedule counts as a preemption. The walking task stays a holdout and
stalls every synchronize_rcu_tasks() caller, ftrace and BPF trampoline
teardown included, until the syscall returns [1].
cond_resched_tasks_rcu_qs() is the usual tool for that [2]. It reports
the quiescent state at each yield and still reschedules as
cond_resched() does on PREEMPT_NONE and PREEMPT_VOLUNTARY kernels.

Fixes: 057996380a ("bpf: Add batch ops to all htab bpf map")
Cc: "Paul E. McKenney" <paulmck@kernel.org>
Cc: Rik van Riel <riel@surriel.com>
Link: https://lore.kernel.org/bpf/20260715215314.44423f47@fangorn/ [1]
Link: https://lore.kernel.org/bpf/9d444098-7c03-4163-af12-bd0a79a51443@paulmck-laptop/ [2]
Assisted-by: LLM
Signed-off-by: Jose Fernandez (Anthropic) <jose.fernandez@linux.dev>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Rik van Riel <riel@surriel.com>
Link: https://lore.kernel.org/r/20260909-b4-htab-batch-resched-v2-1-0cb529d8f95a@toxicpanda.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-12 10:30:50 -07:00
Siddharth Chintamaneni
ac781acaef selftests/bpf: Test terminal gotox instructions
Add tests that place gotox at the end of the main program and a
subprogram, with each jump-table target preceding the gotox instruction.
This tests gotox as a valid non-fallthrough terminal instruction.

Signed-off-by: Siddharth Chintamaneni <sidchintamaneni@gmail.com>
Reviewed-by: Anton Protopopov <a.s.protopopov@gmail.com>
Link: https://lore.kernel.org/r/20260902171414.96165-2-sidchintamaneni@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-12 10:26:05 -07:00
Siddharth Chintamaneni
0d7823cd4c bpf: Allow terminal gotox instructions
check_subprogs() treats gotox as a direct jump and validates its reserved
zero offset. When gotox is the final instruction, this produces a
synthetic successor one instruction past the end of the subprogram and
rejects an otherwise valid program.

Skip direct-offset validation for gotox and accept it as a
non-fallthrough terminal instruction. Its actual targets remain validated
from the instruction-array jump table during CFG construction.

Fixes: 493d9e0d60 ("bpf, x86: add support for indirect jumps")
Signed-off-by: Siddharth Chintamaneni <sidchintamaneni@gmail.com>
Reviewed-by: Anton Protopopov <a.s.protopopov@gmail.com>
Link: https://lore.kernel.org/r/20260902171414.96165-1-sidchintamaneni@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-12 10:26:05 -07:00
Alexei Starovoitov
15071f2a12 Merge branch 'bpf-tcp-fix-bpf_sock_destroy-on-time_wait-and-listener-socks'
Jiayuan Chen says:

====================
bpf,tcp: Fix bpf_sock_destroy() on TIME_WAIT and listener socks

Fix two bugs in bpf_sock_destroy(). One is an out-of-bounds read of
sk->sk_protocol on TIME_WAIT and NEW_SYN_RECV socks, since the field is
not in struct sock_common. The other is a might_sleep splat when
destroying a listener with children in its accept queue, the
cond_resched() in inet_csk_listen_stop() runs under the iterator's
rcu_read_lock(). Patch 3 adds a subtest for each.

v2 -> v3:
 - Patch 1: add Reviewed-by from Kuniyuki.
 - Patch 2: reword why cond_resched() has to go, it can reschedule or
   report a bogus quiescent state there.
 - Patch 2: keep the cond_resched() for the non-BPF path rather than
   removing it as Kuniyuki suggested. VOLUNTARY and NONE are still
   there on some arches, and on x86 in stable where this goes, so a
   big listener close() still relies on it. Can go once those modes
   are gone.
 - Selftest: don't leak the fd if accept() unexpectedly succeeds.
v2: https://lore.kernel.org/bpf/20260906074135.185212-1-jiayuan.chen@linux.dev/

v1 -> v2:
 - Patch 1: fix the return comment too.
 - Patch 2: new.
 - Selftest: server recv()s EOF before close so the FINs can't cross,
   comment style, keep the blank line before RUN_TESTS(), add the
   tcp_listen_pending subtest.
v1: https://lore.kernel.org/bpf/20260903125306.299943-1-jiayuan.chen@linux.dev/
====================

Link: https://patch.msgid.link/20260910112107.148770-1-jiayuan.chen@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-10 16:58:40 -07:00
Jiayuan Chen
8036d3a5a6 selftests/bpf: Test bpf_sock_destroy() on TIME_WAIT and listener socks
Add two subtests.

tcp_timewait: the client shuts down first and the server closes after
it, so the client sock ends up in TIME_WAIT. A tcp iterator then finds
the timewait sock by the cookie it inherited from the client sock and
destroys it. Iterate once more to make sure it is gone. Without the
first fix bpf_sock_destroy() reads past the timewait sock and KASAN
complains.

tcp_listen_pending: connect to a listener but never accept, so the child
sits in the accept queue, then destroy the listener. Without the second
fix the cond_resched() in inet_csk_listen_stop() trips the might_sleep
check under rcu_read_lock().

  ./test_progs -a sock_destroy

  #444/1   sock_destroy/tcp_client:OK
  #444/2   sock_destroy/tcp_server:OK
  #444/3   sock_destroy/tcp_listen_pending:OK
  #444/4   sock_destroy/tcp_timewait:OK
  #444/5   sock_destroy/udp_client:OK
  #444/6   sock_destroy/udp_server:OK
  #444/7   sock_destroy/trace_tcp_destroy_sock:OK
  #444     sock_destroy:OK
  Summary: 1/7 PASSED, 0 SKIPPED, 0/0 FAILED

Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Link: https://lore.kernel.org/r/20260910112810.153801-1-jiayuan.chen@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-10 16:58:40 -07:00
Jiayuan Chen
eaab8cab45 tcp: Skip cond_resched() in inet_csk_listen_stop() under BPF context
bpf_sock_destroy() runs from the tcp iterator, under rcu_read_lock(). If
the sock is a listener that still has children in its accept queue,
tcp_abort() ends up in inet_csk_listen_stop() and the cond_resched()
there trips the debug check:

BUG: sleeping function called from invalid context at net/ipv4/inet_connection_sock.c:1523
in_atomic(): 0, irqs_disabled(): 0, non_block: 0, pid: 628, name: test_progs
preempt_count: 0, expected: 0
RCU nest depth: 1, expected: 0
locks held by test_progs/628: 3, last CPU#3:
 #0: ffff8881158cee18 (&p->lock){+.+.}-{4:4}, at: bpf_seq_read+0x56/0x1210
 #1: ffff8881106bb858 (sk_lock-AF_INET6){+.+.}-{0:0}, at: bpf_iter_tcp_seq_show+0x32b/0x4b0
 #2: ffffffffb435af20 (rcu_read_lock){....}-{1:3}, at: bpf_iter_run_prog+0x46b/0xde0
CPU: 3 UID: 0 PID: 628 Comm: test_progs Tainted: G        W           7.2.0+ #65 PREEMPT
Tainted: [W]=WARN
Call Trace:
 <TASK>
 dump_stack_lvl+0xc1/0xf0
 dump_stack+0x10/0x20
 __might_resched+0x3d2/0x610
 inet_csk_listen_stop+0x7b/0xbf0
 tcp_abort+0x23b/0x3b0
 bpf_sock_destroy+0xfc/0x140
 bpf_prog_448133d24601754f_iter_tcp6_server+0x81/0x8a
 bpf_iter_run_prog+0x538/0xde0
 bpf_iter_tcp_seq_show+0x26b/0x4b0
 bpf_seq_read+0x424/0x1210
 vfs_read+0x197/0xe40
 ksys_read+0x119/0x240
 __x64_sys_read+0x72/0xc0
 x64_sys_call+0x647/0x27e0
 do_syscall_64+0xe5/0x610
 entry_SYSCALL_64_after_hwframe+0x76/0x7e
RIP: 0033:0x7fad39b28aca
RSP: 002b:00007ffc381c61c0 EFLAGS: 00000246 ORIG_RAX: 0000000000000000
RAX: ffffffffffffffda RBX: 00007ffc381c6a88 RCX: 00007fad39b28aca
RDX: 0000000000000032 RSI: 00007ffc381c6250 RDI: 0000000000000014
RBP: 00007ffc381c61e0 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000003
R13: 0000000000000000 R14: 000055f077c1bbb0 R15: 00007fad3a0f3000
 </TASK>

The commit that added the kfunc already guards lock_sock() in tcp_abort()
and udp_abort() with has_current_bpf_ctx(), but missed the listener path.
Do the same for the cond_resched(). The loop runs inside the iterator's
rcu_read_lock(), it must not reschedule or report a quiescent state there.

Fixes: 4ddbcb8862 ("bpf: Add bpf_sock_destroy kfunc")
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Link: https://lore.kernel.org/r/20260910112736.153710-1-jiayuan.chen@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-10 16:58:40 -07:00
Jiayuan Chen
01b245ba01 bpf: Fix out-of-bounds read of sk_protocol in bpf_sock_destroy()
sk_protocol lives in struct sock, not in struct sock_common. A timewait
or request sock handed to bpf_sock_destroy() by the tcp iterator is
neither, so reading sk->sk_protocol runs past the object:

==================================================================
BUG: KASAN: slab-out-of-bounds in bpf_sock_destroy+0xc7/0xe0
Read of size 2 at addr ffff8881047d11b4 by task test_progs/428

Tainted: [W]=WARN
Call Trace:
 <TASK>
 dump_stack_lvl+0x91/0xf0
 print_report+0xd1/0x630
 kasan_report+0xf3/0x130
 __asan_report_load2_noabort+0x14/0x30
 bpf_sock_destroy+0xc7/0xe0
 bpf_prog_c3dd61f9d9cd9f37_iter_tcp6_timewait+0x9f/0xb7
 bpf_iter_run_prog+0x538/0xde0
 bpf_iter_tcp_seq_show+0x26b/0x4b0
 bpf_seq_read+0x424/0x1210
 vfs_read+0x197/0xe40
 ksys_read+0x119/0x240
 __x64_sys_read+0x72/0xc0
 x64_sys_call+0x647/0x27e0
 do_syscall_64+0xe5/0x610
 entry_SYSCALL_64_after_hwframe+0x76/0x7e

Only check sk_protocol on full socks. tcp_abort() already knows how to
deal with TIME_WAIT and NEW_SYN_RECV socks. Also fix the comment, it
never matched the code.

Fixes: 4ddbcb8862 ("bpf: Add bpf_sock_destroy kfunc")
Reported-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
Closes: https://lore.kernel.org/bpf/20260702224519.800135-1-xmei5@asu.edu/
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://lore.kernel.org/r/20260910112634.152195-1-jiayuan.chen@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-10 16:58:40 -07:00
Jiayuan Chen
f77d212457 selftests/bpf: Test BTF walk into a flexible array of zero-sized elements
The program stashes a bpf_obj_new() object whose type ends with a flexible
array of empty structs, then reads it back as an untrusted kptr. Without
the previous patch this divides by zero in btf_struct_walk() instead of
being rejected.

  # ./test_progs -t verifier_btf_flex_array
  ...
  #602     verifier_btf_flex_array:OK
  Summary: 1/1 PASSED, 0 SKIPPED, 0/0 FAILED

Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Link: https://lore.kernel.org/r/20260910122316.186384-2-jiayuan.chen@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-10 16:58:05 -07:00
Jiayuan Chen
b0b3dc6652 bpf: Fix divide-by-zero in btf_struct_walk()
When an access goes past the struct and the last member is a flexible
array, btf_struct_walk() folds the offset back into a single element with
(off - moff) % t->size, but never checks that the element type has a size.

BTF takes an empty struct, so this in program BTF

	/* event could be empty */
	struct event {
 #ifdef HAVE_TIMESTAMP
		__u64 ts;
 #endif
	};

	struct batch {
		int nr;
		struct event events[];
	};

divides by zero at prog load time. Getting there needs a PTR_TO_BTF_ID that
is not MEM_ALLOC, e.g. a plain read of a local kptr stashed in a map from a
sleepable program.

Oops: divide error: 0000 [#1] SMP KASAN PTI
RIP: 0010:btf_struct_walk+0x53f/0x1570
Call Trace:
 <TASK>
 btf_struct_access+0x42a/0xcd0
 check_ptr_to_btf_access+0x4dc/0x1160
 check_mem_access+0x3a45/0x8740
 check_load_mem+0x36a/0xd10
 do_check_common+0x3ef0/0xb210
 bpf_check+0x6d3b/0x8580
 bpf_prog_load+0xf7c/0x2720
 __sys_bpf+0xa83/0x3690
 __x64_sys_bpf+0xc7/0x150
 x64_sys_call+0x1f3f/0x27e0
 do_syscall_64+0xe5/0x610
 entry_SYSCALL_64_after_hwframe+0x76/0x7e
 </TASK>

Reject a zero-sized element type. The fixed array path in the same function
already bails out on the same thing:

	btf_struct_walk()
	...
		/* skip empty array */
		if (moff == mtrue_end)
			continue;

		msize /= total_nelems;

Fixes: 9c5f8a1008 ("bpf: Support variable length array in tracing programs")
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260910122316.186384-1-jiayuan.chen@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-10 16:58:05 -07:00
Daniel Borkmann
2936aed9b0 bpf: Clear scalar delta on narrowing stack spill
check_stack_write_fixed_off() breaks the scalar link on a narrowing spill
by zeroing the id of the destination stack slot, but leaves the delta in
place. save_register_state() has just copied the source register verbatim,
so the slot keeps the BPF_ADD_CONST delta of a register it is no longer
linked to. This is the same shape as the case addressed in 1b327732c8
("bpf: Clear delta when clearing reg id for non-{add,sub} ops"). Unlike
the latter, no miscomputation seems reachable, so mainly consistency.

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260910185604.44949-1-daniel@iogearbox.net
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-10 16:57:28 -07:00
Daniel Borkmann
a903f145a8 selftests/bpf: Add tests for the KF_PERFMON gates
Add test cases where each one loads with CAP_BPF alone and checks that
the program is correctly rejected.

  # LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_kfunc_perfmon
  [...]
  #627/1   verifier_kfunc_perfmon/rdonly_cast_noperfmon:OK
  #627/2   verifier_kfunc_perfmon/rdonly_cast_noperfmon @unpriv:OK
  #627/3   verifier_kfunc_perfmon/probe_read_kernel_dynptr_noperfmon:OK
  #627/4   verifier_kfunc_perfmon/probe_read_kernel_dynptr_noperfmon @unpriv:OK
  #627/5   verifier_kfunc_perfmon/stream_vprintk_noperfmon:OK
  #627/6   verifier_kfunc_perfmon/stream_vprintk_noperfmon @unpriv:OK
  #627/7   verifier_kfunc_perfmon/get_kmem_cache_noperfmon:OK
  #627/8   verifier_kfunc_perfmon/get_kmem_cache_noperfmon @unpriv:OK
  #627/9   verifier_kfunc_perfmon/arg_untrusted_read_noperfmon:OK
  #627/10  verifier_kfunc_perfmon/arg_untrusted_read_noperfmon @unpriv:OK
  #627     verifier_kfunc_perfmon:OK
  Summary: 1/10 PASSED, 0 SKIPPED, 0/0 FAILED

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/r/20260910213510.49358-4-daniel@iogearbox.net
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-10 16:55:48 -07:00
Daniel Borkmann
f9191460cd bpf: Require CAP_PERFMON for untrusted read-only memory reads
Marking bpf_rdonly_cast() KF_PERFMON CAP-limits one producer of PTR_TO_MEM |
MEM_RDONLY | PTR_UNTRUSTED, but not the type itself. A global subprogram
argument tagged __arg_untrusted results in the same register with no kfunc
call.

Reported-by: STAR Labs SG <info@starlabs.sg>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/r/20260910213510.49358-3-daniel@iogearbox.net
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-10 16:55:47 -07:00
Daniel Borkmann
81c975aae3 bpf: Require CAP_PERFMON for kfuncs reading memory
Mark fault-safe probe reading kfuncs as KF_PERFMON, similarly as we do for
the old-style BPF helper equivalents. bpf_rdonly_cast() is included in this
list as well as it returns PTR_TO_MEM | MEM_RDONLY | PTR_UNTRUSTED for an
unchecked object and is using fault-safe BPF_PROBE_MEM.

Note that only the void form of bpf_rdonly_cast() produced a register that
was readable without CAP_PERFMON. For a struct type id the kfunc returns
PTR_TO_BTF_ID | PTR_UNTRUSTED, whose dereference has always been gated in
check_ptr_to_btf_access(). The flag is not conditional on the type id, so
for the latter it only moves the rejection from the dereference to the call
itself, which is the better place to report it anyway.

The bpf_stream_vprintk() and bpf_stream_print_stack() kfuncs are marked
as well. The former ends up in the same bpf_bprintf_prepare() as the
bpf_snprintf() helper, where %pks, %pus and %pI4 read through a program-
supplied address and %pB resolves one into a symbol. The latter walks the
stack and prints each instruction pointer via %pS.

Lastly, bpf_get_kmem_cache() takes a raw scalar address that the verifier
does not constrain and dereferences the page/slab metadata for it. Field
reads on the returned pointer are still blocked (PTR_TO_BTF_ID | PTR_UNTRUSTED
-> check_ptr_to_btf_access() results in -EPERM without the CAP), but the
NULL/non-NULL result is observable.

Reported-by: STAR Labs SG <info@starlabs.sg>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/r/20260910213510.49358-2-daniel@iogearbox.net
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-10 16:55:47 -07:00
Daniel Borkmann
88ce88e933 bpf: Add KF_PERFMON kfunc flag
Tracing related BPF helpers e.g. under bpf_base_func_proto() are gated
behind CAP_PERFMON. However, the same is currently not true for kfuncs
and they are accessible via plain CAP_BPF. Add a new KF_PERFMON flag
which can be used such that check_kfunc_call() ensures env->allow_ptr_leaks
is permitted. This follows similar pattern to existing KF_DESTRUCTIVE flag.

The rejection returns -EPERM to match the other CAP_PERFMON gates in the
verifier, that is, check_ptr_to_btf_access() and check_ptr_to_map_access(),
which report the very same policy to user space.

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/r/20260910213510.49358-1-daniel@iogearbox.net
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-10 16:55:47 -07:00
Weiming Shi
e4a62833ad bpf: Disallow bpf_skb_pull_data() for LWT_SEG6LOCAL
An LWT_SEG6LOCAL program can invalidate its cached SRH with
bpf_lwt_seg6_adjust_srh() and then call bpf_skb_pull_data(). The latter
may reallocate skb->head, leaving the per-CPU SRH pointer dangling.
Post-program SRH validation then writes through that pointer.

Disallow bpf_skb_pull_data() for LWT_SEG6LOCAL programs so the verifier
rejects this unsafe helper combination. Other LWT program types continue
to expose the helper through lwt_out_func_proto().

Fixes: 004d4b274e ("ipv6: sr: Add seg6local action End.BPF")
Reported-by: co+adfca3e91be95776@bugs.sh
Suggested-by: Alexei Starovoitov <alexei.starovoitov@gmail.com>
Signed-off-by: Weiming Shi <bestswngs@gmail.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Closes: https://lore.kernel.org/all/GCy0KRM2IcQGoJQTjJEU9D0maBxXzEDHuQpq@bugs.sh/
Link: https://lore.kernel.org/bpf/DL9COXZQXX4V.1FN45QO2Q77ZH@gmail.com/
Link: https://lore.kernel.org/bpf/20260909040807.3885815-2-bestswngs@gmail.com
2026-09-09 20:35:42 +02:00
Daniel Borkmann
15e2565f1c selftests/bpf: Add test for bpf_skb_change_tail on csum partial skbs
Add a test which builds an ICMP error out of a TCP segment. A tcx prog
on the client's egress side trims the first data segment down to the
target size and pushes the ICMP error headers in front of it to then
reflect the packet back to the sender.

  # LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t tc_change_tail
  [...]
  #509     tc_change_tail:OK
  #510     tc_change_tail_pmtu:OK
  Summary: 2/0 PASSED, 0 SKIPPED, 0/0 FAILED

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/r/20260907121025.1923656-2-daniel@iogearbox.net
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-07 19:33:06 -07:00
Daniel Borkmann
3b55f350c6 bpf: Fix bpf_skb_change_tail wrt csum partial skbs
Cilium generates ICMP "frag needed" replies from BPF when a LB DSR
packet exceeds the egress MTU. The reply is built by first trimming the
packet down to target size via bpf_skb_change_tail(), and then pushing
the ICMP error headers in front of it.

The trim is rejected for skbs which carry a checksum offload, e.g. TCP
packets aggregated by GRO on ingress where tcp_gro_complete() leaves
the skb as CHECKSUM_PARTIAL. __bpf_skb_min_len() raises the minimum
length to the end of the L4 checksum field, so a trim to 42 bytes bails
out with -EINVAL given a min_len of 52 in this case, and due to that
the ICMP generator fails. This is not the case if GRO is turned off.

Fix this bpf_skb_change_tail() restriction and drop the checksum offload
when the new length no longer covers the checksum field. The BPF program
rewrites the skb into an ICMP error and computes the checksum itself
anyway.

Fixes: 5293efe62d ("bpf: add bpf_skb_change_tail helper")
Reported-by: Tom Hadlaw <tom.hadlaw@isovalent.com>
Reported-by: Yusuke Suzuki <yusuke.suzuki@isovalent.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/r/20260907121025.1923656-1-daniel@iogearbox.net
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2026-09-07 19:33:06 -07:00
Linus Torvalds
df2908090c Linux 7.3-rc2 2026-09-06 15:07:20 -07:00
Linus Torvalds
b1e00ffaf9 tracing fixes for v7.3:
- Fix several tracefs files that did not take the trace_array reference
 
   A trace instance can be created and destroyed in the tracefs "instances"
   directory via mkdir and rmdir respectively. The instance is represented by
   a trace_array descriptor. Most tracefs files pass the trace_array as the
   private data of the inode to the open/read/write functions. Since there is
   no locking between the time a task opens a file and the deletion of the
   instance (and the freeing of the trace_array), each open needs to get a
   reference to the trace_array and each close must remove it. A instance
   can't be removed if there's any reference taken on its trace_array. The
   open function uses trace_array_get() that takes a lock (preventing removal
   of instances) and iterates the list of all existing trace_arrays and if it
   finds a match, it takes the reference and releases the lock. If it doesn't
   find a match, it causes the open to return -ENODEV.
 
   There were some added files that did not take the trace_array reference
   on open that needed to be fixed. Sashiko also correctly pointed out that
   there were some files that took an address of an field or element of the
   trace_array which had a pointer back to the trace_array to take its
   reference on open. But this leaves a slight race between referencing this
   element to get the trace_array as the element itself could be freed. To
   solve this, some helper functions were created to look for trace_arrays
   with this field or element in the search so that the element did not have
   to be dereferenced before the trace_array's reference was taken.
 
 - Add a lock around ftrace_ops initialization
 
   When a ftrace_ops is first used by ftrace, some internal initialization is
   performed on the ops. But if multiple tasks were calling functions that
   did this initialization, it could race and perform doing the
   initialization more than once, corrupting the internal data. Add a lock in
   the initialization code to prevent this from happening.
 
 - Fix splice reads on mmapped buffers
 
   The logic in the ring buffer splice code for mmapped buffers is supposed
   to do a copy of the memory as the mapped buffers can't be given to splice.
   But there was an if statement within the copy code that would return a -1
   if a request for a full page was done and it wasn't a partial read. This
   is because this logic was written before mmapped buffers existed and this
   case didn't make sense at the time. For mmapped buffers it makes perfect
   sense and by returning early can drop a lot of pages unnecessarily.
 
 - Have the persistent ring buffer validation check nr_subbufs
 
   Sashiko reported that the validation code was relying on the saved
   nr_subbufs to match the calculated nr_pages + 1 and if they were off, that
   the code could cause corruption. Sashiko is correct, and the saved
   nr_subbufs should be validated before assuming it is correct.
 
 - Do not allow more than one instance with the same name on cmdline
 
   If an admin were to add more than one trace instances with the same name
   they all would be created, but only the first one would be accessible via
   tracefs. This used to not be allowed but some restructuring of code has
   since made it possible.
 
 - Fix the race between subbuf resize and trace_pipe_raw readers
 
   If a task was reading trace_pipe_raw while another task was changing the
   ring buffer subbuf size, it could crash the reader. The trace_pipe_raw
   readers do get their own copy of the page from the buffer, but the code
   needs some restructuring to not have the resize of the subbuffers cause
   issues.
 
 - Cap the size of the mapped (static) ring buffer nr_pages
 
   The meta data used for ring buffer mapped buffers is 32 bit in size. A
   normal ring buffer could (in theory) have more than 4 billion pages.
   But this is not allowed by mapped buffers, so enforce it.
 -----BEGIN PGP SIGNATURE-----
 
 iIoEABYKADIWIQRRSw7ePDh/lE+zeZMp5XQQmuv6qgUCap3GJRQccm9zdGVkdEBn
 b29kbWlzLm9yZwAKCRAp5XQQmuv6qtAfAP9hDPtzctAoz+IHZq+GYejhKTu99ICG
 vAxTOZivuG6KYAD/UPA4P7z5ayxGM5UlT+2U81+mpCd55F2oFiIxRuFYcwk=
 =/d+T
 -----END PGP SIGNATURE-----

Merge tag 'trace-v7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull tracing fixes from Steven Rostedt:

 - Fix several tracefs files that did not take the trace_array reference

   A trace instance can be created and destroyed in the tracefs
   "instances" directory via mkdir and rmdir respectively. The instance
   is represented by a trace_array descriptor.

   Most tracefs files pass the trace_array as the private data of the
   inode to the open/read/write functions. Since there is no locking
   between the time a task opens a file and the deletion of the instance
   (and the freeing of the trace_array), each open needs to get a
   reference to the trace_array and each close must remove it.

   An instance can't be removed if there's any reference taken on its
   trace_array. The open function uses trace_array_get() that takes a
   lock (preventing removal of instances) and iterates the list of all
   existing trace_arrays and if it finds a match, it takes the reference
   and releases the lock. If it doesn't find a match, it causes the open
   to return -ENODEV.

   There were some added files that did not take the trace_array
   reference on open that needed to be fixed. Sashiko also correctly
   pointed out that there were some files that took an address of an
   field or element of the trace_array which had a pointer back to the
   trace_array to take its reference on open. But this leaves a slight
   race between referencing this element to get the trace_array as the
   element itself could be freed. To solve this, some helper functions
   were created to look for trace_arrays with this field or element in
   the search so that the element did not have to be dereferenced before
   the trace_array's reference was taken.

 - Add a lock around ftrace_ops initialization

   When a ftrace_ops is first used by ftrace, some internal
   initialization is performed on the ops. But if multiple tasks were
   calling functions that did this initialization, it could race and
   perform doing the initialization more than once, corrupting the
   internal data. Add a lock in the initialization code to prevent this
   from happening.

 - Fix splice reads on mmapped buffers

   The logic in the ring buffer splice code for mmapped buffers is
   supposed to do a copy of the memory as the mapped buffers can't be
   given to splice. But there was an if statement within the copy code
   that would return a -1 if a request for a full page was done and it
   wasn't a partial read. This is because this logic was written before
   mmapped buffers existed and this case didn't make sense at the time.
   For mmapped buffers it makes perfect sense and by returning early can
   drop a lot of pages unnecessarily.

 - Have the persistent ring buffer validation check nr_subbufs

   Sashiko reported that the validation code was relying on the saved
   nr_subbufs to match the calculated nr_pages + 1 and if they were off,
   that the code could cause corruption. Sashiko is correct, and the
   saved nr_subbufs should be validated before assuming it is correct.

 - Do not allow more than one instance with the same name on cmdline

   If an admin were to add more than one trace instances with the same
   name they all would be created, but only the first one would be
   accessible via tracefs. This used to not be allowed but some
   restructuring of code has since made it possible.

 - Fix the race between subbuf resize and trace_pipe_raw readers

   If a task was reading trace_pipe_raw while another task was changing
   the ring buffer subbuf size, it could crash the reader. The
   trace_pipe_raw readers do get their own copy of the page from the
   buffer, but the code needs some restructuring to not have the resize
   of the subbuffers cause issues.

 - Cap the size of the mapped (static) ring buffer nr_pages

   The meta data used for ring buffer mapped buffers is 32 bit in size.
   A normal ring buffer could (in theory) have more than 4 billion
   pages. But this is not allowed by mapped buffers, so enforce it.

* tag 'trace-v7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
  ring-buffer: Use a macro for static buffer bits
  tracing: Fix comment in tracing_buffers_splice_read()
  ring-buffer: Prevent truncation of nr_pages / nr_subbufs
  ring-buffer: Cap static ring buffer nr_pages
  tracing: Fix subbuf resize races with trace_pipe_raw readers
  tracing: Fix to avoid creating trace instances with duplicate names
  ring-buffer: Add checking nr_subbufs to persistent ring buffer validation
  ring-buffer: Allow splice reads on static buffers
  tracing: Take trace_array reference when opening options file
  ftrace: Synchronize the initialization of ftrace_ops
  ftrace: Take trace_array reference before accessing its ftrace_ops
  tracing: Have show_event_filters/triggers files take trace array ref
2026-09-06 14:21:24 -07:00
Linus Torvalds
2beb1b31a1 bpf-fixes
-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE+soXsSLHKoYyzcli6rmadz2vbToFAmqdhRMACgkQ6rmadz2v
 bTo8vRAAnP+x1z6FBOgHawGmmBpXtazoipRFeok/+/YGQ4SbS+evvFNvmkeCyihZ
 7EeNHGuWEbA6xQBAcMf0StMjmr3jkJvUA6lsHSxBiFLpHGqNt0Fz9IXvAL/8QWPg
 F7+CBs5A+J61i66LEmINbWzW1ujDf7baU/1VWui9zfPxnmPu40V/74eXzm6DmH/V
 oHTsCscCYNe+N+Wix6B6nLrObY537fcJU12N56uqpkaSc0+6H1fBQJmyFGpYroTX
 +4g+DNzEHyIYmt6B3+oDpbT0Zh/pP6ROq5TPDNJSSa+5B/uPo5C5pH520HwXF9hJ
 04uaD7y2fpE809Nwl3OEK4ozpJ+mEGU1NKZPvFAxckY6GCiBtfbGd1etFno7r+4F
 mZhNBKbQVEQX4XJUlcoqn9n7T2OCDnjiuneZAjIi4vUdevnSnakr0rCTFriiHP54
 jg4fEkXxvYjPiqs5SQbxoGxmYSfg9fYaSfK4HgFdlfbwp+3Vmv4BW/tcsIJ9dcPs
 L3YWkUU3znjbu2BLy0CP9fGt/1ik8p4/tA8vvZwz0yqpDMJkLy1TziGMef51UQ7k
 1Pe/Ln5J3C6xnWs+3TRF11y8PuuCF0y47DGPACfwPoQxca1ufJ5fgmLXRRQToZe4
 RjDmoeQvvI9w9kxh6gVhTHoiiEeD0wcQqx2CMHKTrU/PbM7d4Co=
 =oz4Z
 -----END PGP SIGNATURE-----

Merge tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf

Pull bpf fixes from Alexei Starovoitov:
 "This mainly contains verifier fixes that address bugs reported by
  Nicholas Carlini.

   - Fix incorrect non-NULL inference in pointer comparisons: pointer
     types that may be NULL at runtime, pointers with unbounded offsets,
     JMP32 comparisons with zero, and imprecise zero registers (Eduard
     Zingerman)

   - Fix precision tracking for half-dead zero spills, ld_abs/ld_ind
     implicit subprog exit, bpf_loop() callbacks, linked scalar ids and
     NULL call arguments (Eduard Zingerman)

   - Reject BPF_PSEUDO_FUNC reference to the main program, fix zero
     extension of arena 32-bit cmpxchg, don't rewrite bpf_fastcall
     patterns entered by a jump (Eduard Zingerman)

   - Fix percpu map update and BPF_F_CPU validation with sparse CPU IDs
     (Hui Su)

   - Fix NULL-ptr-derefs in bpf_snprintf_btf() for void and VAR types,
     and reject key-less BTF for hash maps (Jiayuan Chen)

   - Various fixes (Kumar Kartikeya Dwivedi):
       - Fix out-of-bounds access in disassembler on invalid LDSX
         instruction
       - mark siginfo of signal tracepoints as scalar and
         sched_process_wait argument as nullable
       - mark faultable stack helpers as sleepable
       - reject tail calls and legacy packet loads from callbacks
       - enforce rbtree callback lock restrictions for resilient locks
       - require MEM_PERCPU for percpu kptr stores
       - clear NON_OWN_REF after RCU protection ends
       - mark NULL kptr stores precise
       - preserve inner map identity in callback frames
       - reject non-scalar bpf_loop() iteration counts

   - Fix trampoline allocation slowdown on x86 by using
     EXECMEM_MODULE_DATA (Mike Rapoport)

   - Keep bpf_refcount_acquire() nullable for borrowed RCU kptrs and
     reject untrusted allocated-object pointers (Ning Ding)

   - Fix special fields handling in recycled rhtab elements (Nuoqi Gui,
     Yuan Chen)"

* tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: (86 commits)
  bpf, riscv: Make arena support depend on ZACAS
  selftests/bpf: Test pointer bpf_loop iteration count rejection
  bpf: Reject non-scalar bpf_loop iteration counts
  bpf: use mark_arg_precision() in check_mem_size_reg()
  bpf: propagate mark_chain_precision() errors out of loop_flag_is_zero()
  selftests/bpf: precision of a NULL global subprogram BTF_ID argument
  bpf: mark a NULL BTF_ID argument of a global subprogram precise
  selftests/bpf: precision of a NULL kfunc argument
  bpf: mark a NULL kfunc argument precise
  selftests/bpf: precision of a NULL global subprogram memory argument
  bpf: mark a NULL memory argument of a call precise
  selftests/bpf: precision of a NULL helper argument
  bpf: mark a NULL call argument precise
  selftests/bpf: Test inner map identities in callbacks
  bpf: Preserve inner map identity in callback frames
  selftests/bpf: Test imprecise scalar kptr stores
  bpf: Mark NULL kptr stores precise
  selftests/bpf: Test rhtab kptr cancellation semantics
  bpf: Cancel special fields when recycling rhtab elements
  selftests/bpf: Test timer field on recycled rhtab element
  ...
2026-09-06 13:49:44 -07:00
Linus Torvalds
88405f0ad1 Miscellaneous scheduler fixes:
- Fix a timestamping bug in pick_task_fair() and
    yield_task_fair() (Zhan Xusheng)
 
  - Skip migrate-disabled tasks when picking a push
    candidate in the RT and DL schedulers (Seiji Nishikawa)
 
  - Skip rq->avg_idle update without a valid idle_stamp
    (Shubhang Kaushik)
 
  - Fix throttling bug in throttle_cfs_rq(), caused
    by the recent single-runqueue conversion (Wanwu Li)
 
  - Fix bandwidth calculation bug in distribute_cfs_runtime(),
    caused by the single-runqueue conversion (Wanwu Li)
 
  - Don't make x86 ITMT enablement depend on debugfs (Mario Limonciello)
 
  - Avoid creating misfits during cache-aware load-balancing
    on hybrid systems (Tim Chen)
 
 Signed-off-by: Ingo Molnar <mingo@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCgAvFiEEBpT5eoXrXCwVQwEKEnMQ0APhK1gFAmqdTLIRHG1pbmdvQGtl
 cm5lbC5vcmcACgkQEnMQ0APhK1gdURAAnjK4q2xg115VyKOvg4u4epPre1XNK4a/
 RmimS/2+1fm7/5zqOXOQG3qU8z2Aj+nBIZa1d1yadV7ARHSymDINobCX+2HQ1DjU
 Iysk2BqbbLnQQNKh81OBWhPMyJy4yOnig/670KR5JdFAdTKFYW/Ys+pQmO9M6rEx
 hc8B4SUhOGeRnonfPMTbFW7H9eopWzst8kIpF0USl58az0mla5tkooWYJsvSuUHn
 g4s9IALlRe3DxgmMT3kLKoAx2+ySnrzZNRs+M8Z/sMSDKXCMFpvX36wOqBJMHwXe
 ZoAow/fJh4ysoYTR7luhDIBDQAkszf4GE9a644I/Bd0sIIYKs4+1RW1T3DAoWmKv
 Sx0C29MM4Ng4R3lPx2avb+c0T0VO080/3fqRFrGrck8BIpMa9HcinOxf6etI8+vt
 STnz5uQZZj3V+A5vzlKCAFGUUqK/s3EJnrT5z4VPxXmY2ZSyLLub4C5SQ8RNnqRL
 u+Q9ra9DYBJh/HJTgjjcAP/HxmKK5LyQXd2DzuA1wy/wwC+s7TtPrxN5ep5EdZmv
 K65zGGo28BgcCKD8jc1DfVXf8cf80fMiAr4fruGdo5TVwPyBahwZBi4sbqhahtqL
 D4QwCsbOfhS+evVpx29n+V7eQzZzvSdN1tFCtZ3Tg6VvT9aJ2jLSx79aCsL/cYbr
 hViB9N0yhGk=
 =8l0J
 -----END PGP SIGNATURE-----

Merge tag 'sched-urgent-2026-09-06' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull scheduler fixes from Ingo Molnar:

 - Fix a timestamping bug in pick_task_fair() and yield_task_fair()
   (Zhan Xusheng)

 - Skip migrate-disabled tasks when picking a push candidate in the
   RT and DL schedulers (Seiji Nishikawa)

 - Skip rq->avg_idle update without a valid idle_stamp (Shubhang
   Kaushik)

 - Fix throttling bug in throttle_cfs_rq(), caused by the recent
   single-runqueue conversion (Wanwu Li)

 - Fix bandwidth calculation bug in distribute_cfs_runtime(),
   caused by the single-runqueue conversion (Wanwu Li)

 - Don't make x86 ITMT enablement depend on debugfs (Mario Limonciello)

 - Avoid creating misfits during cache-aware load-balancing on hybrid
   systems (Tim Chen)

* tag 'sched-urgent-2026-09-06' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  sched/fair: Avoid creating misfits during cache-aware balancing
  x86/itmt: Don't make ITMT enablement depend on debugfs
  sched/fair: Use cfs_rq->h_curr in distribute_cfs_runtime()
  sched/fair: Use cfs_rq->h_curr in throttle_cfs_rq()
  sched/core: Skip rq->avg_idle update without a valid idle_stamp
  sched/rt,dl: Skip migrate-disabled tasks when picking a push candidate
  sched/fair: Use update_curr_eevdf() for the remaining root cfs_rq callers
2026-09-06 11:08:44 -07:00
Linus Torvalds
c4a3928e7d Misc perf events fixes:
- Skip empty AUX records with only format flags
    (Leo Yan)
 
  - Fix use-after-free when perf mmap() revival races with the
    last munmap() (Yilin Zhang, Weiming Shi)
 
 Signed-off-by: Ingo Molnar <mingo@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCgAvFiEEBpT5eoXrXCwVQwEKEnMQ0APhK1gFAmqdSokRHG1pbmdvQGtl
 cm5lbC5vcmcACgkQEnMQ0APhK1gRKRAAkDxFT3BNAtAypk5CvTPeO9K530u38mqc
 fIvYQYbYkqIMZaFSmIthSgsPOJD/mqkccl1sd6djlS/73mI/X8eXCwZOgjLnaCsu
 jRx8atD8Q7hHeyJ78qY/hFsyHPTQel5+cniEk4BjUrYIYhHklFfpQw1AZhoJieUs
 vnqkDGMY/qHQ5pGs+dnz3oI8FE6ruNU0Ps6qiBqsbsvMJI+wviCidpC6BqluyxvQ
 Pp6ACwqQIiH2mPwI9WYtHKmVL5ajQJPt8fbIwIvRbX5wCY566zb79oUys2pNUh/U
 zzpTNOGgqtVCTgiuMiEI2SlIIMzC36P071vBTyD8YZWUNpdYXLM20RdvAUZkqefT
 Vx3cMs8rgcPnjGO4XhPJJOzfyyCi25VL/p3af9S3wSJhfQNdMF9BuqRABFMBmtDi
 5adP+4p5Dw9sfc2+F2/OCT7PrXsFiNsOp+iduWJYb6i8hdSjV1mfjGLyptdBCdj2
 dUYr4VrFoiYUVLPWJD5F4/dDAIljN3CEoGwHiOITNCYu0fgO7GCALf8FG5U9Ec7D
 guuRGnEXDFQDCOZHm5MuVYWAR7qPhe+iVoX6Dw9ZmgecGWb4eTl4A5e8LGgbcbJ1
 JMfVr3OENSyGi1dPnCX4DEsIpeXN1UTMHhrwNosWcu1OrEEUkzdQ8GQ17qU6PURG
 yYSXCvhdEtY=
 =Ffvz
 -----END PGP SIGNATURE-----

Merge tag 'perf-urgent-2026-09-06' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf events fixes from Ingo Molnar:

 - Skip empty AUX records with only format flags (Leo Yan)

 - Fix use-after-free when perf mmap() revival races with the
   last munmap() (Yilin Zhang, Weiming Shi)

* tag 'perf-urgent-2026-09-06' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  perf: Fix use-after-free when perf mmap() revival races with the last munmap()
  perf/core: Skip empty AUX records with only format flags
2026-09-06 11:06:09 -07:00
Linus Torvalds
c8990f3179 Misc locking fixes:
- Fix a softirq processing delay bug in local_interrupt_disable(),
    which should mostly only affect the Rust runtime (Boqun Feng)
 
  - Remove the hardirq_disable_count() function which caused the
    previous bug and is now unused & unnecessary (Boqun Feng)
 
  - lockdep: Invalidate stale class_cache entries for zapped classes
    (Eric Dumazet)
 
  - Fix rt_mutex specific futex scheduling helpers
    (Sebastian Andrzej Siewior)
 
  - Fix rcuwait use-after-free race during futex requeue PI (Yao Kai)
 
 Signed-off-by: Ingo Molnar <mingo@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCgAvFiEEBpT5eoXrXCwVQwEKEnMQ0APhK1gFAmqdSKMRHG1pbmdvQGtl
 cm5lbC5vcmcACgkQEnMQ0APhK1gh6hAAtIhAm10pkx7JG4Kl+SQArmoAxNMfW9X1
 grx50dn1/LFuIF0upooJwJmLMBpPMmxcpYPWbg5nTUsx+wDqcJTT0T7Aw2iZN2f+
 OdODMOGNuQU4IUxDC+qX+fkgHvRFzng0zhSXYL2kGpQJHktrFMAHn90+5aO9SEgA
 XcSjmDacTxfJADNk43snrlHy6t+yOXBEmIrhicnbh11GFNIXLbvdGW/0SObU0Q5o
 WdwGHTZRFAM3mpX7xMSFOKypM+Gt4pXdQ/uC1PQg0B/AT35p4zsYIdcht/cBMHp0
 93eTeJd9ede410t3hL1Hnsuo1zf5qHtCgBukS+UHJWoWpnSOMgT2iaBx2X3jIsev
 ptPIqV5Alq8O+tnNOSDOwD2HH2drAdUBVH+gZ/yKMDbk9jfw9eZKqRw628U2P7rG
 mD5CLzpmfj0mMAuqcOhhdqSQmPhjp2Y8Ju/8UAMSmcocvqjQBxvouNS3Tby9U5v+
 R4CsuUwtnYpMyy5xyRrnwVsaE3le5fvneXCmCokk8FtQ8as/4ATd+cG+RROSa3vW
 /AAjrB1HBQqyseE8lki4LFFmlr01Otc8u6pASy4/pxeuKMA9hSuLC3RuEfVetW6W
 BcK4BCIJBy6chcsCBxv0F7FgI/y7/bpVyBmoTkW3Sb0I23xswXzTzbucn/dPJNdl
 oqFj3KQygxw=
 =vEuZ
 -----END PGP SIGNATURE-----

Merge tag 'locking-urgent-2026-09-06' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull locking fixes from Ingo Molnar:

 - Fix a softirq processing delay bug in local_interrupt_disable(),
   which should mostly only affect the Rust runtime (Boqun Feng)

 - Remove the hardirq_disable_count() function which caused the
   previous bug and is now unused & unnecessary (Boqun Feng)

 - lockdep: Invalidate stale class_cache entries for zapped classes
   (Eric Dumazet)

 - Fix rt_mutex specific futex scheduling helpers
   (Sebastian Andrzej Siewior)

 - Fix rcuwait use-after-free race during futex requeue PI (Yao Kai)

* tag 'locking-urgent-2026-09-06' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  futex: Prevent rcuwait use-after-free during requeue PI
  futex: Provide rt_mutex_.*_schedule() equivalents for futex scheduling
  locking/lockdep: Invalidate stale class_cache entries for zapped classes
  preempt: Remove hardirq_disable_count()
  interrupt: Disable interrupt before modifying hardirq_disable counter
2026-09-06 10:45:46 -07:00