All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH bpf-next v2 00/17] bpf: Indirect calls of bpf subprogs (callx)
@ 2026-09-24  3:10 Alexei Starovoitov
  2026-09-24  3:10 ` [PATCH bpf-next v2 01/17] bpf: Fix infinite loop in check_max_stack_depth() Alexei Starovoitov
                   ` (17 more replies)
  0 siblings, 18 replies; 36+ messages in thread
From: Alexei Starovoitov @ 2026-09-24  3:10 UTC (permalink / raw)
  To: bpf; +Cc: daniel, andrii, eddyz87, memxor

From: Alexei Starovoitov <ast@kernel.org>

v1->v2:
- Dropped "bpf: Don't fold loads from insn_array maps into constants".
  bpf_map_direct_read() rejects insn_array already.
- patch 1: emit the same diag as sort_subprogs_topo() (bpf-ci).
- patch 3 is new: taking the address of a function that is never called
  hit verifier_bug() in jit_subprogs(). Not related to callx, but callx
  makes it likely.
- patch 4: BPF_OP() == BPF_CALL in liveness like in const_fold, explained
  in the comment why slots are live before callx callsite (Eduard).
- patch 5: moved !bpf_is_callx() into nested 'if' (Eduard). JIT support
  is checked before the type of the register.
- patch 6: sync callbacks are in the call graph too. Stack depth of
  a callback whose address is read from .rodata or taken in another
  subprog was not accounted.
- patch 10:
  . check_cfg() explores functions of a table one at a time. It was
    losing changes_pkt_data and other effects of the functions in
    a table that call each other.
  . no cmpxchg64(), it's not available on all 32-bit archs.
  . don't reject the prog that reads a pointer to a function that was
    removed as dead code (sashiko).
  . load of the pointer sets jit_required, so the prog that passes it to
    a helper as a callback can't run in the interpreter (bpf-ci).
  . tbl[i].data at variable offset is a regular load when none of
    the possible offsets overlaps with a pointer (bpf-ci).
- patch 12: append the functions and copy the map only for progs that
  have callx. The rest use .rodata as-is (bpf-ci). Pass token_fd to map
  create. Dropped dead bpf_map_lookup_elem() fallback.
- patch 14: light skeleton reserves fd_array slots only when the object
  has callx.
- selftests: anchored callx_retval_is_tracked to the caller, the tests
  of global func in a table and of const folding of the pointer test what
  they claim now, skip without JIT, fixed ASSERT_GT() of u32 and
  the comment, added tests for the above (bpf-ci). The table in
  callx_rodata_lskel test is volatile. clang was turning it into
  direct calls, so the test didn't test light skeleton.
- Added acks.
v1: https://lore.kernel.org/bpf/20260922011323.1298619-1-alexei.starovoitov@gmail.com/

Introduce BPF_JMP | BPF_CALL | BPF_X 'callx dst_reg' instruction: indirect
call of bpf subprog with address in a register. LLVM emits it for calls
via function pointer. The verifier rejected it as unknown opcode.

Only static subprogs can be called. The callee is verified in the context
of the caller like a direct call of static subprog. No callx into global
subprogs, helpers or kfuncs.

All callees are known before the main verifier pass. The address of
the callee comes from:

- ld_imm64 BPF_PSEUDO_FUNC, which is allowed for static subprogs only.
  add_subprogs() and check_cfg() see them already.

- 64-bit load from read-only data: tables of functions, struct ops,
  vtables, where pointers are mixed with other data. Rust needs that:

    r6 = vtable ll
    r1 = *(u64 *)(r6 + 0)      // data
    r2 = *(u64 *)(r6 + 8)      // pointer to a function
    callx r2

  libbpf keeps the data in a frozen read-only array map, one per prog
  that has callx, and stores byte offset of static function in the prog
  into the pointer. Progs without callx use .rodata as before.
  The kernel guesses pointers by that value before check_cfg() (patch 10).
  Wrong guess is safe. Functions referenced by data only are found via
  func_info (patch 9). After JIT the kernel replaces the offsets in
  the map with addresses. The prog must be the only user of the map,
  since other progs would have been verified with its old content. The
  prog reads addresses as data, so CAP_PERFMON is required.

Both produce PTR_TO_FUNC.

The passes before the main one don't know the callee and treat callx
conservatively (patch 4). The main pass records caller -> callee edges.
Recursion and stack depth checks use them afterwards (patch 6).

In C:

  static const struct shape_ops square_ops = { 1, area, 10, perimeter };
  ...
  return ops->area(x) * ops->scale + ops->perimeter(ops->id);

and

  static int (* const handlers[])(struct xdp_md *) = { foo, bar, baz };
  ...
  if (i < ARRAY_SIZE(handlers))
          return handlers[i](ctx);

plus what clang compiles without data: picking one of several functions,
passing a function pointer into another function.

Patches 1-3 are fixes I hit along the way: a prog without callx that
hangs bpf_prog_load() in check_max_stack_depth(), its test, and
verifier_bug() when the address of a function that is never called is
taken.

Not supported:
- JITs other than x86-64 and arm64. No interpreter support.
- x86-64 with FineIBT: bpf_jit_supports_callx() returns false.
- tail calls in callees of callx.
- pointers to functions in writable data, misaligned pointers.

Alexei Starovoitov (17):
  bpf: Fix infinite loop in check_max_stack_depth()
  selftests/bpf: Test recursion through a global function and a callback
  bpf: Keep functions with address taken when removing dead code
  bpf: Prepare static analysis passes for callx instruction
  bpf: Add callx instruction to call bpf subprogs indirectly
  bpf: Add callx calls to the call graph
  bpf, x86: Add JIT support for callx
  bpf, arm64: Add JIT support for callx
  bpf: Discover subprogs described by func_info
  bpf: Recognize pointers to functions in read-only maps
  libbpf: Support pointers to static functions in data when linking
  libbpf: Resolve pointers to functions in read-only data
  libbpf: Treat .data.rel.ro as read-only data
  libbpf: Support pointers to functions in read-only data in light
    skeleton
  selftests/bpf: Add tests for callx
  selftests/bpf: Add tests for callx through pointers in read-only data
  bpf, docs: Document callx instruction

 Documentation/bpf/clang-notes.rst             |    7 +-
 Documentation/bpf/linux-notes.rst             |   31 +-
 arch/arm64/net/bpf_jit_comp.c                 |   16 +
 arch/x86/net/bpf_jit_comp.c                   |   68 ++
 include/linux/bpf.h                           |   10 +
 include/linux/bpf_verifier.h                  |   42 +
 include/linux/filter.h                        |    1 +
 kernel/bpf/backtrack.c                        |   20 +-
 kernel/bpf/cfg.c                              |   76 ++
 kernel/bpf/const_fold.c                       |    6 +-
 kernel/bpf/core.c                             |   12 +
 kernel/bpf/disasm.c                           |    5 +-
 kernel/bpf/fixups.c                           |   94 +-
 kernel/bpf/liveness.c                         |   38 +-
 kernel/bpf/verifier.c                         |  714 ++++++++++-
 tools/lib/bpf/bpf_gen_internal.h              |   13 +-
 tools/lib/bpf/gen_loader.c                    |  172 ++-
 tools/lib/bpf/libbpf.c                        |  443 ++++++-
 tools/lib/bpf/linker.c                        |   18 +
 tools/testing/selftests/bpf/Makefile.skel     |    2 +-
 .../bpf/prog_tests/callx_func_ptr_map.c       |  202 ++++
 .../bpf/prog_tests/callx_rodata_lskel.c       |   63 +
 .../selftests/bpf/prog_tests/verifier.c       |   12 +
 .../selftests/bpf/progs/callx_rodata.c        |   51 +
 .../selftests/bpf/progs/verifier_callx.c      | 1039 +++++++++++++++++
 .../bpf/progs/verifier_callx_rodata.c         |  846 ++++++++++++++
 .../bpf/progs/verifier_global_subprogs.c      |   31 +
 .../selftests/bpf/verifier/basic_call.c       |    2 +-
 28 files changed, 3913 insertions(+), 121 deletions(-)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/callx_func_ptr_map.c
 create mode 100644 tools/testing/selftests/bpf/prog_tests/callx_rodata_lskel.c
 create mode 100644 tools/testing/selftests/bpf/progs/callx_rodata.c
 create mode 100644 tools/testing/selftests/bpf/progs/verifier_callx.c
 create mode 100644 tools/testing/selftests/bpf/progs/verifier_callx_rodata.c


base-commit: b4d936547f5a3ca5563f48ee81f153c928336027
-- 
2.55.0


^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2026-09-29 16:40 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-24  3:10 [PATCH bpf-next v2 00/17] bpf: Indirect calls of bpf subprogs (callx) Alexei Starovoitov
2026-09-24  3:10 ` [PATCH bpf-next v2 01/17] bpf: Fix infinite loop in check_max_stack_depth() Alexei Starovoitov
2026-09-24  3:10 ` [PATCH bpf-next v2 02/17] selftests/bpf: Test recursion through a global function and a callback Alexei Starovoitov
2026-09-24  3:10 ` [PATCH bpf-next v2 03/17] bpf: Keep functions with address taken when removing dead code Alexei Starovoitov
2026-09-24  3:10 ` [PATCH bpf-next v2 04/17] bpf: Prepare static analysis passes for callx instruction Alexei Starovoitov
2026-09-24  3:56   ` bot+bpf-ci
2026-09-24  4:18   ` Eduard Zingerman
2026-09-24  3:10 ` [PATCH bpf-next v2 05/17] bpf: Add callx instruction to call bpf subprogs indirectly Alexei Starovoitov
2026-09-24  3:28   ` sashiko-bot
2026-09-24  3:10 ` [PATCH bpf-next v2 06/17] bpf: Add callx calls to the call graph Alexei Starovoitov
2026-09-24  3:26   ` sashiko-bot
2026-09-24  3:56   ` bot+bpf-ci
2026-09-24  5:00   ` Eduard Zingerman
2026-09-24  3:10 ` [PATCH bpf-next v2 07/17] bpf, x86: Add JIT support for callx Alexei Starovoitov
2026-09-24  5:33   ` Eduard Zingerman
2026-09-24  3:10 ` [PATCH bpf-next v2 08/17] bpf, arm64: " Alexei Starovoitov
2026-09-24  3:10 ` [PATCH bpf-next v2 09/17] bpf: Discover subprogs described by func_info Alexei Starovoitov
2026-09-24  5:42   ` Eduard Zingerman
2026-09-24  3:10 ` [PATCH bpf-next v2 10/17] bpf: Recognize pointers to functions in read-only maps Alexei Starovoitov
2026-09-24  3:10 ` [PATCH bpf-next v2 11/17] libbpf: Support pointers to static functions in data when linking Alexei Starovoitov
2026-09-24  3:10 ` [PATCH bpf-next v2 12/17] libbpf: Resolve pointers to functions in read-only data Alexei Starovoitov
2026-09-24  3:27   ` sashiko-bot
2026-09-24  3:10 ` [PATCH bpf-next v2 13/17] libbpf: Treat .data.rel.ro as " Alexei Starovoitov
2026-09-24  3:10 ` [PATCH bpf-next v2 14/17] libbpf: Support pointers to functions in read-only data in light skeleton Alexei Starovoitov
2026-09-24  3:10 ` [PATCH bpf-next v2 15/17] selftests/bpf: Add tests for callx Alexei Starovoitov
2026-09-24  3:56   ` bot+bpf-ci
2026-09-24  3:10 ` [PATCH bpf-next v2 16/17] selftests/bpf: Add tests for callx through pointers in read-only data Alexei Starovoitov
2026-09-24  3:10 ` [PATCH bpf-next v2 17/17] bpf, docs: Document callx instruction Alexei Starovoitov
2026-09-24  5:50 ` [PATCH bpf-next v2 00/17] bpf: Indirect calls of bpf subprogs (callx) patchwork-bot+netdevbpf
2026-09-24  5:55   ` Eduard Zingerman
2026-09-24  6:00     ` Alexei Starovoitov
2026-09-24 17:50   ` Ihor Solodrai
2026-09-24 18:09     ` Alexei Starovoitov
2026-09-28 23:13   ` Ihor Solodrai
2026-09-29  6:04     ` Alexei Starovoitov
2026-09-29 16:40       ` Ihor Solodrai

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.