Added selftests to check for nested deadlocks in queue and stack maps. test_map_queue_stack_nesting_success:PASS:test_queue_stack_nested_map__open 0 nsec test_map_queue_stack_nesting_success:PASS:test_queue_stack_nested_map__load 0 nsec test_map_queue_stack_nesting_success:PASS:test_queue_stack_nested_map__attach 0 nsec test_map_queue_stack_nesting_success:PASS:MAP Write 0 nsec test_map_queue_stack_nesting_success:PASS:no map nesting 0 nsec test_map_queue_stack_nesting_success:PASS:no map nesting 0 nsec 384/1 test_queue_stack_nested_map/map_queue_nesting:OK test_map_queue_stack_nesting_success:PASS:test_queue_stack_nested_map__open 0 nsec test_map_queue_stack_nesting_success:PASS:test_queue_stack_nested_map__load 0 nsec test_map_queue_stack_nesting_success:PASS:test_queue_stack_nested_map__attach 0 nsec test_map_queue_stack_nesting_success:PASS:MAP Write 0 nsec test_map_queue_stack_nesting_success:PASS:no map nesting 0 nsec 384/2 test_queue_stack_nested_map/map_stack_nesting:OK 384 test_queue_stack_nested_map:OK Summary: 1/2 PASSED, 0 SKIPPED, 0 FAILED Signed-off-by: Siddharth Chintamaneni <sidchintamaneni@xxxxxxxxx> --- samples/bpf/Makefile | 3 + .../prog_tests/test_queue_stack_nested_map.c | 69 +++++++++++ .../bpf/progs/test_queue_stack_nested_map.c | 116 ++++++++++++++++++ 3 files changed, 188 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/test_queue_stack_nested_map.c create mode 100644 tools/testing/selftests/bpf/progs/test_queue_stack_nested_map.c diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 9aa027b144df..9e1abf0e21ad 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -7,6 +7,7 @@ pound := \# # List of programs to build tprogs-y := test_lru_dist +tprogs-y += sid_queue_stack tprogs-y += sock_example tprogs-y += fds_example tprogs-y += sockex1 @@ -98,6 +99,7 @@ ibumad-objs := ibumad_user.o hbm-objs := hbm.o $(CGROUP_HELPERS) xdp_router_ipv4-objs := xdp_router_ipv4_user.o $(XDP_SAMPLE) +sid_queue_stack-objs := sid_queue_stack_user.o # Tell kbuild to always build the programs always-y := $(tprogs-y) @@ -149,6 +151,7 @@ always-y += task_fd_query_kern.o always-y += ibumad_kern.o always-y += hbm_out_kern.o always-y += hbm_edt_kern.o +always-y += sid_queue_stack_kern.o TPROGS_CFLAGS = $(TPROGS_USER_CFLAGS) TPROGS_LDFLAGS = $(TPROGS_USER_LDFLAGS) diff --git a/tools/testing/selftests/bpf/prog_tests/test_queue_stack_nested_map.c b/tools/testing/selftests/bpf/prog_tests/test_queue_stack_nested_map.c new file mode 100644 index 000000000000..fc46561788af --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/test_queue_stack_nested_map.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <test_progs.h> +#include <network_helpers.h> + +#include "test_queue_stack_nested_map.skel.h" + + +static void test_map_queue_stack_nesting_success(bool is_map_queue) +{ + struct test_queue_stack_nested_map *skel; + int err; + + skel = test_queue_stack_nested_map__open(); + if (!ASSERT_OK_PTR(skel, "test_queue_stack_nested_map__open")) + return; + + err = test_queue_stack_nested_map__load(skel); + if (!ASSERT_OK(err, "test_queue_stack_nested_map__load")) + goto out; + + skel->bss->pid = getpid(); + err = test_queue_stack_nested_map__attach(skel); + if (!ASSERT_OK(err, "test_queue_stack_nested_map__attach")) + goto out; + + /* trigger map from userspace to check nesting */ + int value = 0; + + do { + if (is_map_queue) { + err = bpf_map_update_elem(bpf_map__fd(skel->maps.map_queue), + NULL, &value, 0); + if (err < 0) + break; + err = bpf_map_lookup_and_delete_elem(bpf_map__fd(skel->maps.map_queue), + NULL, &value); + } else { + err = bpf_map_update_elem(bpf_map__fd(skel->maps.map_stack), + NULL, &value, 0); + if (err < 0) + break; + err = bpf_map_lookup_and_delete_elem(bpf_map__fd(skel->maps.map_stack), + NULL, &value); + } + } while (0); + + + if (!ASSERT_OK(err, "MAP Write")) + goto out; + + if (is_map_queue) { + ASSERT_EQ(skel->bss->err_queue_push, -EBUSY, "no map nesting"); + ASSERT_EQ(skel->bss->err_queue_pop, -EBUSY, "no map nesting"); + } else { + ASSERT_EQ(skel->bss->err_stack, -EBUSY, "no map nesting"); + } +out: + test_queue_stack_nested_map__destroy(skel); +} + +void test_test_queue_stack_nested_map(void) +{ + if (test__start_subtest("map_queue_nesting")) + test_map_queue_stack_nesting_success(true); + if (test__start_subtest("map_stack_nesting")) + test_map_queue_stack_nesting_success(false); + +} + diff --git a/tools/testing/selftests/bpf/progs/test_queue_stack_nested_map.c b/tools/testing/selftests/bpf/progs/test_queue_stack_nested_map.c new file mode 100644 index 000000000000..893a37593206 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_queue_stack_nested_map.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "vmlinux.h" +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> + +struct { + __uint(type, BPF_MAP_TYPE_STACK); + __uint(max_entries, 32); + __uint(key_size, 0); + __uint(value_size, sizeof(__u32)); +} map_stack SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_QUEUE); + __uint(max_entries, 32); + __uint(key_size, 0); + __uint(value_size, sizeof(__u32)); +} map_queue SEC(".maps"); + + +int err_queue_push; +int err_queue_pop; +int err_stack; +int pid; +__u32 trigger_flag_queue_push; +__u32 trigger_flag_queue_pop; +__u32 trigger_flag_stack; + +SEC("fentry/queue_stack_map_push_elem") +int BPF_PROG(test_queue_stack_push_trigger, raw_spinlock_t *lock, unsigned long flags) +{ + + if ((bpf_get_current_pid_tgid() >> 32) != pid) + return 0; + + + trigger_flag_queue_push = 1; + + return 0; +} + +SEC("fentry/queue_map_pop_elem") +int BPF_PROG(test_queue_pop_trigger, raw_spinlock_t *lock, unsigned long flags) +{ + + if ((bpf_get_current_pid_tgid() >> 32) != pid) + return 0; + + trigger_flag_queue_pop = 1; + + return 0; +} + + +SEC("fentry/stack_map_pop_elem") +int BPF_PROG(test_stack_pop_trigger, raw_spinlock_t *lock, unsigned long flags) +{ + + if ((bpf_get_current_pid_tgid() >> 32) != pid) + return 0; + + trigger_flag_stack = 1; + + return 0; +} + +SEC("fentry/_raw_spin_unlock_irqrestore") +int BPF_PROG(test_queue_pop_nesting, raw_spinlock_t *lock, unsigned long flags) +{ + __u32 val; + + if ((bpf_get_current_pid_tgid() >> 32) != pid || trigger_flag_queue_pop != 1) + return 0; + + + err_queue_pop = bpf_map_pop_elem(&map_queue, &val); + + trigger_flag_queue_pop = 0; + + return 0; +} + +SEC("fentry/_raw_spin_unlock_irqrestore") +int BPF_PROG(test_stack_nesting, raw_spinlock_t *lock, unsigned long flags) +{ + __u32 val; + + if ((bpf_get_current_pid_tgid() >> 32) != pid || trigger_flag_stack != 1) + return 0; + + + err_stack = bpf_map_pop_elem(&map_stack, &val); + + trigger_flag_stack = 0; + + return 0; +} + + +SEC("fentry/_raw_spin_unlock_irqrestore") +int BPF_PROG(test_queue_push_nesting, raw_spinlock_t *lock, unsigned long flags) +{ + __u32 val = 1; + + if ((bpf_get_current_pid_tgid() >> 32) != pid || trigger_flag_queue_push != 1) { + return 0; + } + + err_queue_push = bpf_map_push_elem(&map_queue, &val, 0); + + trigger_flag_queue_push = 0; + + return 0; +} + +char _license[] SEC("license") = "GPL"; -- 2.44.0