[PATCH bpf v5 0/3] bpf: Fix use-after-free of progs detached from busy trampolines
Florent Revest (Anthropic)
florent.revest at linux.dev
Sat Sep 26 06:55:57 PDT 2026
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 patching detached progs out of the
images that still call them and patch 3 adds a selftest for the sleeping
case.
Since v3, only the nop of the prog that is detached is patched, in every
image that isn't freed yet, like v2 did. Progs that stay attached keep
running for the tasks that are in old images, ip_after_call is gone and
the call to the original function is never skipped.
On riscv and loongarch a jump of any range takes several instructions,
and as bpf-ci and Alexei pointed out, a task preempted in the middle of
such a patch site could resume into half of the new sequence. v5 makes
the skip sites a single instruction there, patched to a jal / b through
a new arch_bpf_trampoline_skip() hook, like their jump labels. I could
only test these two under qemu.
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). On x86_64, 18
fsession progs with cookies on an 11 argument function still fit in the
image. Same on bpf-next, where patch 2 has trivial context conflicts in
the x86 and arm64 JITs.
Changes since v4
(https://lore.kernel.org/bpf/20260925100342.481242-1-florent.revest@linux.dev/):
- riscv, loongarch: single instruction skip sites, patched through
arch_bpf_trampoline_skip(), loongarch keeps its limit of 38 (bpf-ci,
Alexei)
- arm64: say in bpf_arch_text_poke() why patching out a detached prog
needs no synchronization (bpf-ci)
- Comment fixes (bpf-ci)
- Cc the arch maintainers and lists
Changes since v3
(https://lore.kernel.org/bpf/20260924170543.1017048-1-florent.revest@linux.dev/):
- Only patch the nop of the prog that is detached, in all the images
that aren't freed yet, like v2 did, and explain why a list of images
is needed (Alexei, bpf-ci)
- Lower BPF_MAX_TRAMP_LINKS to 36 on x86, the worst case no longer fit
in a page with the nops (bpf-ci, Alexei)
- selftest: wait for the detached progs to really be freed before
releasing the task, the grace period of patch 1 made the previous wait
too short (bpf-ci). Detach two progs one after the other, so that the
second detach has to reach an image that isn't the current one anymore
- Keep a single comment block in bpf_tramp_image_put() (bpf-ci)
Changes since v2
(https://lore.kernel.org/bpf/20260912095924.866254-1-florent.revest@linux.dev/):
- 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@linux.dev/):
- 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 detached progs in trampoline images that are still in use
selftests/bpf: Detach a trampoline prog while a task sleeps before it
arch/arm64/net/bpf_jit_comp.c | 37 ++--
arch/loongarch/net/bpf_jit.c | 60 ++++--
arch/powerpc/net/bpf_jit_comp.c | 45 +++--
arch/riscv/net/bpf_jit_comp64.c | 56 ++++--
arch/s390/net/bpf_jit_comp.c | 46 +++--
arch/x86/net/bpf_jit_comp.c | 26 ++-
include/linux/bpf.h | 45 ++++-
kernel/bpf/syscall.c | 19 +-
kernel/bpf/trampoline.c | 85 ++++++--
.../selftests/bpf/prog_tests/bpf_mod_race.c | 34 +---
.../bpf/prog_tests/tramp_prog_detach.c | 188 ++++++++++++++++++
.../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, 572 insertions(+), 155 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: ab39974240a0cff765f3bb9cce81d8001ffdb144
--
2.55.0
More information about the linux-riscv
mailing list