Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Add test for bpf_timer overwriting crash

Add a test that validates that timer value is not overwritten when doing
a copy_map_value call in the kernel. Without the prior fix, this test
triggers a crash.

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20220209070324.1093182-3-memxor@gmail.com

authored by

Kumar Kartikeya Dwivedi and committed by
Alexei Starovoitov
a7e75016 a8abb0c3

+86
+32
tools/testing/selftests/bpf/prog_tests/timer_crash.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <test_progs.h> 3 + #include "timer_crash.skel.h" 4 + 5 + enum { 6 + MODE_ARRAY, 7 + MODE_HASH, 8 + }; 9 + 10 + static void test_timer_crash_mode(int mode) 11 + { 12 + struct timer_crash *skel; 13 + 14 + skel = timer_crash__open_and_load(); 15 + if (!ASSERT_OK_PTR(skel, "timer_crash__open_and_load")) 16 + return; 17 + skel->bss->pid = getpid(); 18 + skel->bss->crash_map = mode; 19 + if (!ASSERT_OK(timer_crash__attach(skel), "timer_crash__attach")) 20 + goto end; 21 + usleep(1); 22 + end: 23 + timer_crash__destroy(skel); 24 + } 25 + 26 + void test_timer_crash(void) 27 + { 28 + if (test__start_subtest("array")) 29 + test_timer_crash_mode(MODE_ARRAY); 30 + if (test__start_subtest("hash")) 31 + test_timer_crash_mode(MODE_HASH); 32 + }
+54
tools/testing/selftests/bpf/progs/timer_crash.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <vmlinux.h> 4 + #include <bpf/bpf_tracing.h> 5 + #include <bpf/bpf_helpers.h> 6 + 7 + struct map_elem { 8 + struct bpf_timer timer; 9 + struct bpf_spin_lock lock; 10 + }; 11 + 12 + struct { 13 + __uint(type, BPF_MAP_TYPE_ARRAY); 14 + __uint(max_entries, 1); 15 + __type(key, int); 16 + __type(value, struct map_elem); 17 + } amap SEC(".maps"); 18 + 19 + struct { 20 + __uint(type, BPF_MAP_TYPE_HASH); 21 + __uint(max_entries, 1); 22 + __type(key, int); 23 + __type(value, struct map_elem); 24 + } hmap SEC(".maps"); 25 + 26 + int pid = 0; 27 + int crash_map = 0; /* 0 for amap, 1 for hmap */ 28 + 29 + SEC("fentry/do_nanosleep") 30 + int sys_enter(void *ctx) 31 + { 32 + struct map_elem *e, value = {}; 33 + void *map = crash_map ? (void *)&hmap : (void *)&amap; 34 + 35 + if (bpf_get_current_task_btf()->tgid != pid) 36 + return 0; 37 + 38 + *(void **)&value = (void *)0xdeadcaf3; 39 + 40 + bpf_map_update_elem(map, &(int){0}, &value, 0); 41 + /* For array map, doing bpf_map_update_elem will do a 42 + * check_and_free_timer_in_array, which will trigger the crash if timer 43 + * pointer was overwritten, for hmap we need to use bpf_timer_cancel. 44 + */ 45 + if (crash_map == 1) { 46 + e = bpf_map_lookup_elem(map, &(int){0}); 47 + if (!e) 48 + return 0; 49 + bpf_timer_cancel(&e->timer); 50 + } 51 + return 0; 52 + } 53 + 54 + char _license[] SEC("license") = "GPL";