[PATCH bpf v3 0/3] bpf: Fix use-after-free of progs detached from busy trampolines

From: Florent Revest (Anthropic)

Date: Thu Sep 24 2026 - 13:17:54 EST


A task running in a trampoline image can call a prog that was detached
and freed in the meantime, when it slept in a sleepable prog before
reaching the detached one or was preempted right before calling it.
Patch 1 handles the preempted case with an RCU tasks grace period,
patch 2 handles the sleeping case by extending the ip_after_call nop
patching to every prog in the image and patch 3 adds a selftest for the
sleeping case.

v2 only patched the nop of the detached prog, at detach time, in the
images still in use, which needed the trampoline to track them. v3 goes
with Alexei's simpler proposal: bpf_tramp_image_put() patches all the
nops of the image it retires, the same way it patched ip_after_call,
which goes away. A task that is in an old image when the trampoline is
updated now skips the rest of that image's progs, attached or not, like
it already skipped its fexit progs.

v3 doesn't jump over the call to the original function. With a fexit
prog on a regular kernel function that call is the function itself, so a
task that is before it in an old image would return to its caller
without the function having run. The fentry_fexit subtest of patch 3
checks that it still runs.

sashiko noted that on riscv and loongarch a task can be preempted in
the middle of a multi-instruction patch site. ip_after_call has this too
and it isn't addressed here, pending input from the JIT maintainers on
whether a single instruction site is fine for these in-image jumps.

Tested on x86_64 under KVM and on arm64, s390x, powerpc64le, riscv64
and loongarch64 under qemu TCG, all with KASAN: the new selftest crashes
the unpatched kernel and passes with the series on every one of them,
along with trampoline_count, fentry/fexit, fentry_fexit, modify_return
and lsm_cgroup (and the full test_progs on x86_64). Same on bpf-next,
where patch 2 has a trivial conflict in x86's
arch_bpf_trampoline_size().

Changes since v2
(https://lore.kernel.org/bpf/20260912095924.866254-1-florent.revest@xxxxxxxxx/):
- Patch all the nops in bpf_tramp_image_put() instead of the detached
prog's nop at detach time, drop the image list, the trampoline
backpointer and ip_after_call (Alexei)
- Wait for an RCU tasks grace period before freeing progs that were
linked to a trampoline, for tasks preempted right before the enter
helper (Junseo, sashiko)
- Initialize the jit ctx in loongarch's arch_bpf_trampoline_size() and
the dummy image in every arch_bpf_trampoline_size() (bpf-ci)
- selftest: move the userfaultfd helper to testing_helpers.c and share
it with bpf_mod_race, comment fixes (bpf-ci), add a subtest where the
original function runs between the sleeping prog and the detached one

Changes since v1
(https://lore.kernel.org/bpf/20260819122252.1782790-1-florent.revest@xxxxxxxxx/):
- Patch nops in front of detached progs instead of taking prog
references from the image (Alexei)
- Lower BPF_MAX_TRAMP_LINKS on arm64, loongarch and powerpc so the
image still fits in a page
- Explain that the sleepable case doesn't depend on CONFIG_PREEMPTION
(Kumar, Alexei)
- Add a selftest (Jiri, Alexei)
- Add Sechang's Reported-by (Junseo, Kumar)
- Drop Leon's and Kumar's acks since the code changed entirely

Florent Revest (Anthropic) (3):
bpf: Wait for an RCU tasks grace period before freeing trampoline
progs
bpf: Skip the progs of trampoline images that are being freed
selftests/bpf: Detach a trampoline prog while a task sleeps before it

arch/arm64/net/bpf_jit_comp.c | 33 ++--
arch/loongarch/net/bpf_jit.c | 45 ++---
arch/powerpc/net/bpf_jit_comp.c | 45 ++---
arch/riscv/net/bpf_jit_comp64.c | 39 +++--
arch/s390/net/bpf_jit_comp.c | 46 +++--
arch/x86/net/bpf_jit_comp.c | 26 +--
include/linux/bpf.h | 36 +++-
kernel/bpf/syscall.c | 19 ++-
kernel/bpf/trampoline.c | 37 ++--
.../selftests/bpf/prog_tests/bpf_mod_race.c | 34 +---
.../bpf/prog_tests/tramp_prog_detach.c | 158 ++++++++++++++++++
.../selftests/bpf/progs/tramp_prog_detach.c | 56 +++++++
tools/testing/selftests/bpf/testing_helpers.c | 28 ++++
tools/testing/selftests/bpf/testing_helpers.h | 2 +
14 files changed, 453 insertions(+), 151 deletions(-)
create mode 100644 tools/testing/selftests/bpf/prog_tests/tramp_prog_detach.c
create mode 100644 tools/testing/selftests/bpf/progs/tramp_prog_detach.c


base-commit: 5fc5768c7ca92895ccd1de94dc521e5a55ae7896
--
2.55.0