From: Mykyta Yatsenko Verify that resizable hash map can't be used in tracing progs, as it uses bit_spin_lock for per-bucket locking which can deadlock in NMI context. Signed-off-by: Mykyta Yatsenko --- tools/testing/selftests/bpf/prog_tests/verifier.c | 2 + tools/testing/selftests/bpf/progs/verifier_rhash.c | 112 +++++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c index 302286a80154d37e1e81bef405c2806d1310c252..ef42781a9c1856600a52b4d04f78fb0fd7b54bfb 100644 --- a/tools/testing/selftests/bpf/prog_tests/verifier.c +++ b/tools/testing/selftests/bpf/prog_tests/verifier.c @@ -79,6 +79,7 @@ #include "verifier_reg_equal.skel.h" #include "verifier_ref_tracking.skel.h" #include "verifier_regalloc.skel.h" +#include "verifier_rhash.skel.h" #include "verifier_ringbuf.skel.h" #include "verifier_runtime_jit.skel.h" #include "verifier_scalar_ids.skel.h" @@ -222,6 +223,7 @@ void test_verifier_raw_tp_writable(void) { RUN(verifier_raw_tp_writable); } void test_verifier_reg_equal(void) { RUN(verifier_reg_equal); } void test_verifier_ref_tracking(void) { RUN(verifier_ref_tracking); } void test_verifier_regalloc(void) { RUN(verifier_regalloc); } +void test_verifier_rhash(void) { RUN(verifier_rhash); } void test_verifier_ringbuf(void) { RUN(verifier_ringbuf); } void test_verifier_runtime_jit(void) { RUN(verifier_runtime_jit); } void test_verifier_scalar_ids(void) { RUN(verifier_scalar_ids); } diff --git a/tools/testing/selftests/bpf/progs/verifier_rhash.c b/tools/testing/selftests/bpf/progs/verifier_rhash.c new file mode 100644 index 0000000000000000000000000000000000000000..66dda95d56b0544a43682df42381759e0f8c62d6 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/verifier_rhash.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */ +#include +#include +#include "bpf_misc.h" + +struct { + __uint(type, BPF_MAP_TYPE_RHASH); + __uint(max_entries, 1); + __uint(map_flags, BPF_F_NO_PREALLOC); + __type(key, __u32); + __type(value, __u64); +} map_rhash SEC(".maps"); + +SEC("kprobe") +__description("rhash map is forbidden in BPF_PROG_TYPE_KPROBE") +__failure __msg("tracing progs cannot use resizable hash maps yet") +__naked void rhash_forbidden_in_kprobe(void) +{ + asm volatile ( + "r1 = 0;" + "*(u64*)(r10 - 8) = r1;" + "r2 = r10;" + "r2 += -8;" + "r1 = %[map_rhash] ll;" + "call %[bpf_map_lookup_elem];" + "exit;" + : + : __imm(bpf_map_lookup_elem), + __imm_addr(map_rhash) + : __clobber_all); +} + +SEC("tracepoint") +__description("rhash map is forbidden in BPF_PROG_TYPE_TRACEPOINT") +__failure __msg("tracing progs cannot use resizable hash maps yet") +__naked void rhash_forbidden_in_tracepoint(void) +{ + asm volatile ( + "r1 = 0;" + "*(u64*)(r10 - 8) = r1;" + "r2 = r10;" + "r2 += -8;" + "r1 = %[map_rhash] ll;" + "call %[bpf_map_lookup_elem];" + "exit;" + : + : __imm(bpf_map_lookup_elem), + __imm_addr(map_rhash) + : __clobber_all); +} + +SEC("perf_event") +__description("rhash map is forbidden in BPF_PROG_TYPE_PERF_EVENT") +__failure __msg("tracing progs cannot use resizable hash maps yet") +__naked void rhash_forbidden_in_perf_event(void) +{ + asm volatile ( + "r1 = 0;" + "*(u64*)(r10 - 8) = r1;" + "r2 = r10;" + "r2 += -8;" + "r1 = %[map_rhash] ll;" + "call %[bpf_map_lookup_elem];" + "exit;" + : + : __imm(bpf_map_lookup_elem), + __imm_addr(map_rhash) + : __clobber_all); +} + +SEC("raw_tracepoint") +__description("rhash map is forbidden in BPF_PROG_TYPE_RAW_TRACEPOINT") +__failure __msg("tracing progs cannot use resizable hash maps yet") +__naked void rhash_forbidden_in_raw_tp(void) +{ + asm volatile ( + "r1 = 0;" + "*(u64*)(r10 - 8) = r1;" + "r2 = r10;" + "r2 += -8;" + "r1 = %[map_rhash] ll;" + "call %[bpf_map_lookup_elem];" + "exit;" + : + : __imm(bpf_map_lookup_elem), + __imm_addr(map_rhash) + : __clobber_all); +} + +/* Positive test: socket filter programs CAN use rhash maps */ +SEC("socket") +__description("rhash map is allowed in BPF_PROG_TYPE_SOCKET_FILTER") +__success +__naked void rhash_allowed_in_socket(void) +{ + asm volatile ( + "r1 = 0;" + "*(u64*)(r10 - 8) = r1;" + "r2 = r10;" + "r2 += -8;" + "r1 = %[map_rhash] ll;" + "call %[bpf_map_lookup_elem];" + "r0 = 0;" + "exit;" + : + : __imm(bpf_map_lookup_elem), + __imm_addr(map_rhash) + : __clobber_all); +} + +char _license[] SEC("license") = "GPL"; -- 2.53.0