1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ |
3 | |
4 | #include <linux/bpf.h> |
5 | #include <time.h> |
6 | #include <errno.h> |
7 | #include <bpf/bpf_helpers.h> |
8 | #include "bpf_misc.h" |
9 | #include "bpf_tcp_helpers.h" |
10 | |
11 | char _license[] SEC("license" ) = "GPL" ; |
12 | |
13 | struct elem { |
14 | struct bpf_timer t; |
15 | }; |
16 | |
17 | struct { |
18 | __uint(type, BPF_MAP_TYPE_ARRAY); |
19 | __uint(max_entries, 1); |
20 | __type(key, int); |
21 | __type(value, struct elem); |
22 | } timer_map SEC(".maps" ); |
23 | |
24 | __naked __noinline __used |
25 | static unsigned long timer_cb_ret_bad() |
26 | { |
27 | asm volatile ( |
28 | "call %[bpf_get_prandom_u32];" |
29 | "if r0 s> 1000 goto 1f;" |
30 | "r0 = 0;" |
31 | "1:" |
32 | "goto +0;" /* checkpoint */ |
33 | /* async callback is expected to return 0, so branch above |
34 | * skipping r0 = 0; should lead to a failure, but if exit |
35 | * instruction doesn't enforce r0's precision, this callback |
36 | * will be successfully verified |
37 | */ |
38 | "exit;" |
39 | : |
40 | : __imm(bpf_get_prandom_u32) |
41 | : __clobber_common |
42 | ); |
43 | } |
44 | |
45 | SEC("fentry/bpf_fentry_test1" ) |
46 | __log_level(2) |
47 | __flag(BPF_F_TEST_STATE_FREQ) |
48 | __failure |
49 | /* check that fallthrough code path marks r0 as precise */ |
50 | __msg("mark_precise: frame0: regs=r0 stack= before" ) |
51 | __msg(": (85) call bpf_get_prandom_u32#7" ) /* anchor message */ |
52 | /* check that branch code path marks r0 as precise */ |
53 | __msg("mark_precise: frame0: regs=r0 stack= before " ) __msg(": (85) call bpf_get_prandom_u32#7" ) |
54 | __msg("should have been in [0, 0]" ) |
55 | long BPF_PROG2(test_bad_ret, int, a) |
56 | { |
57 | int key = 0; |
58 | struct bpf_timer *timer; |
59 | |
60 | timer = bpf_map_lookup_elem(&timer_map, &key); |
61 | if (timer) { |
62 | bpf_timer_init(timer, &timer_map, CLOCK_BOOTTIME); |
63 | bpf_timer_set_callback(timer, timer_cb_ret_bad); |
64 | bpf_timer_start(timer, 1000, 0); |
65 | } |
66 | |
67 | return 0; |
68 | } |
69 | |