Skip to content

bpf: the verifier gives the result of Linux for test_verifier - #701

Merged
tamnd merged 1 commit into
mainfrom
bpf-verifier
Nov 12, 2026
Merged

tamnd merged 1 commit into
mainfrom
bpf-verifier

Conversation

@tamnd

@tamnd tamnd commented Nov 12, 2026

Copy link
Copy Markdown
Owner

Part of #537 (the verifier item).

This finishes the first part of the eBPF verifier for the program types of #537. For each program of bpf/test_verifier of the types SOCKET_FILTER, CGROUP_SKB, CGROUP_SOCK, CGROUP_SOCK_ADDR and CGROUP_DEVICE, rukernel now accepts or refuses the program as kernel/bpf/verifier.c of Linux does, with the same verifier message. The kselftest boot test now builds and runs test_verifier.

Changes

  • core/rk-bpf/src/verifier.rs:
    • State pruning, as is_state_visited of Linux. At each prune point (the jump targets and the instructions after a jump or a call), the verifier keeps the states that it saw. A path with a state that is equal to a saved state stops. An equal state on the current path is a loop that does not end, and gives "infinite loop detected at insn N" (EINVAL).
    • With CAP_BPF, check_cfg allows back edges, as in Linux. A loop that changes its state goes on to the limit of 1000000 instructions. A function that calls itself makes frames until "the call stack of 9 frames is too deep" (E2BIG).
    • BPF_JSET refines the bounds of the register, and a BPF_JMP32 compare of a register with a 64-bit value that fits in 32 bits refines the bounds as a 64-bit compare.
    • The alignment of the pointers with BPF_F_STRICT_ALIGNMENT and for the atomic instructions, the size and offset rules of each context field (skb_is_valid_access, sock_addr_is_valid_access, with the wide access of the IPv6 fields), and the bounds of map values with the messages of check_mem_region_access.
    • The order of the errors of check_alu_op, check_regno and BPF_LD_IMM64 is as in Linux, so that each refused program gives the first message of Linux.
    • The registers and the stack of a state are on the heap. A debug build of the kernel keeps many copies of a state on the stack, and the 32 KiB kernel stack overflowed.
  • core/rk-bpf/src/test_run.rs, syscall.rs, uapi.rs, attr.rs: BPF_PROG_TEST_RUN, as net/bpf/test_run.c. A socket filter and a CGROUP_SKB program run on a packet from user space that comes in on the loopback device, with repeat, ctx_in and ctx_out. The other program types give ENOTSUPP (524, new in core/rk-abi/src/errno.rs). test_verifier uses this command to run each program that the verifier accepts.
  • core/rk-bpf/src/prog.rs: the fields tstamp, gso_segs, gso_size and hwtstamp of struct __sk_buff.
  • tools/kselftest/build.sh: builds bpf/test_verifier of Linux v6.17 with a static libbpf. It skips the program types that R5 eBPF: the interpreter, maps and cgroup programs #537 does not cover, with the message SKIP (program type N), and it runs without bpf_testmod.ko.
  • tools/kselftest/bpf.md: the result of test_verifier and the reasons for each skip.
  • tests/user/init.c: the checks "the verifier refuses a loop" and "the verifier refuses recursion" now expect the result of Linux with CAP_BPF: "infinite loop detected at insn 10" with EINVAL, and "the call stack of 9 frames is too deep" with E2BIG.

Tests

  • cargo test -p rk-bpf -p rk-abi on server2: 80 and 7 passed. New tests: jset_and_jmp32_refine_the_bounds, the_order_of_the_errors_is_as_in_linux, a_socket_filter_runs_on_the_packet_after_the_ethernet_header, the_errors_of_a_test_run, the_context_of_a_test_run.
  • cargo clippy -p rk-bpf -p rk-syscall -p rk-abi --all-targets on server2: no new warnings. rustfmt --edition 2024 --check is clean on the changed Rust files. Load average of server2: 14.6 to 18.5.
  • x86_64 kselftest boot test with bpf/test_verifier, built on server2 and run on server1: Summary: 281 PASSED, 510 SKIPPED, 0 FAILED. Before this change, 259 passed and 22 failed. tools/kselftest/bpf.md gives the skips. Load average of server1: 2.6 to 3.3.
  • x86_64 ltp boot test with the bpf tests, run on server1: exit 33. bpf_map01 and bpf_prog01 to bpf_prog04 pass. bpf_prog05, bpf_prog06 and bpf_prog07 give TCONF, as on Linux with kernel.unprivileged_bpf_disabled=2, because they drop CAP_BPF. Load average of server1: 0.18 to 0.44.
  • x86_64 cargo xtask boot-test init with RK_CMDLINE="-- only bpf", run on server1: exit 33, "init: each check passed", 94 checks ok. Load average of server1: 0.03 to 0.11.
  • arm64 RK_AARCH64_TESTS=init cargo xtask boot-test aarch64 with RK_CMDLINE="-- only bpf" on server2: pass, "init: each check passed", 94 checks ok. Load average of server2: 5.4 to 5.7.

The full gate did not run.

Add state pruning, the back edge rules of Linux with CAP_BPF, the bounds after BPF_JSET and BPF_JMP32, the alignment and context access rules, and BPF_PROG_TEST_RUN. The kselftest boot test runs bpf/test_verifier: 281 passed and 0 failed for the program types of #537.
@tamnd tamnd added kind/feature New behavior or a new part. area/bpf BPF: the verifier, the JIT, maps and BTF. labels Nov 12, 2026
@tamnd
tamnd merged commit cecdbac into main Nov 12, 2026
6 of 7 checks passed
@tamnd
tamnd deleted the bpf-verifier branch November 12, 2026 02:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/bpf BPF: the verifier, the JIT, maps and BTF. kind/feature New behavior or a new part.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant