Skip to content

Commit acc3c47

Browse files
author
Alexei Starovoitov
committed
Merge branch 'Fix for crash due to overwrite in copy_map_value'
Kumar Kartikeya says: ==================== A fix for an oversight in copy_map_value that leads to kernel crash. Also, a question for BPF developers: It seems in arraymap.c, we always do check_and_free_timer_in_array after we do copy_map_value in map_update_elem callback, but the same is not done for hashtab.c. Is there a specific reason for this difference in behavior, or did I miss that it happens for hashtab.c as well? Changlog: --------- v1 -> v2: v1: https://lore.kernel.org/bpf/[email protected] * Fix build error for selftests patch due to missing SYS_PREFIX in bpf tree ==================== Signed-off-by: Alexei Starovoitov <[email protected]>
2 parents 4a11678 + a7e7501 commit acc3c47

File tree

3 files changed

+88
-1
lines changed

3 files changed

+88
-1
lines changed

include/linux/bpf.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,8 @@ static inline void copy_map_value(struct bpf_map *map, void *dst, void *src)
224224
if (unlikely(map_value_has_spin_lock(map))) {
225225
s_off = map->spin_lock_off;
226226
s_sz = sizeof(struct bpf_spin_lock);
227-
} else if (unlikely(map_value_has_timer(map))) {
227+
}
228+
if (unlikely(map_value_has_timer(map))) {
228229
t_off = map->timer_off;
229230
t_sz = sizeof(struct bpf_timer);
230231
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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";

0 commit comments

Comments
 (0)