1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <vmlinux.h> |
3 | #include <bpf/bpf_tracing.h> |
4 | #include <bpf/bpf_helpers.h> |
5 | #include "../bpf_testmod/bpf_testmod_kfunc.h" |
6 | |
7 | struct map_value { |
8 | struct prog_test_ref_kfunc __kptr *ptr; |
9 | }; |
10 | |
11 | struct { |
12 | __uint(type, BPF_MAP_TYPE_ARRAY); |
13 | __type(key, int); |
14 | __type(value, struct map_value); |
15 | __uint(max_entries, 16); |
16 | } array_map SEC(".maps" ); |
17 | |
18 | static __noinline int cb1(void *map, void *key, void *value, void *ctx) |
19 | { |
20 | void *p = *(void **)ctx; |
21 | bpf_kfunc_call_test_release(p); |
22 | /* Without the fix this would cause underflow */ |
23 | return 0; |
24 | } |
25 | |
26 | SEC("?tc" ) |
27 | int underflow_prog(void *ctx) |
28 | { |
29 | struct prog_test_ref_kfunc *p; |
30 | unsigned long sl = 0; |
31 | |
32 | p = bpf_kfunc_call_test_acquire(scalar_ptr: &sl); |
33 | if (!p) |
34 | return 0; |
35 | bpf_for_each_map_elem(&array_map, cb1, &p, 0); |
36 | bpf_kfunc_call_test_release(p); |
37 | return 0; |
38 | } |
39 | |
40 | static __always_inline int cb2(void *map, void *key, void *value, void *ctx) |
41 | { |
42 | unsigned long sl = 0; |
43 | |
44 | *(void **)ctx = bpf_kfunc_call_test_acquire(scalar_ptr: &sl); |
45 | /* Without the fix this would leak memory */ |
46 | return 0; |
47 | } |
48 | |
49 | SEC("?tc" ) |
50 | int leak_prog(void *ctx) |
51 | { |
52 | struct prog_test_ref_kfunc *p; |
53 | struct map_value *v; |
54 | |
55 | v = bpf_map_lookup_elem(&array_map, &(int){0}); |
56 | if (!v) |
57 | return 0; |
58 | |
59 | p = NULL; |
60 | bpf_for_each_map_elem(&array_map, cb2, &p, 0); |
61 | p = bpf_kptr_xchg(&v->ptr, p); |
62 | if (p) |
63 | bpf_kfunc_call_test_release(p); |
64 | return 0; |
65 | } |
66 | |
67 | static __always_inline int cb(void *map, void *key, void *value, void *ctx) |
68 | { |
69 | return 0; |
70 | } |
71 | |
72 | static __always_inline int cb3(void *map, void *key, void *value, void *ctx) |
73 | { |
74 | unsigned long sl = 0; |
75 | void *p; |
76 | |
77 | bpf_kfunc_call_test_acquire(scalar_ptr: &sl); |
78 | bpf_for_each_map_elem(&array_map, cb, &p, 0); |
79 | /* It should only complain here, not in cb. This is why we need |
80 | * callback_ref to be set to frameno. |
81 | */ |
82 | return 0; |
83 | } |
84 | |
85 | SEC("?tc" ) |
86 | int nested_cb(void *ctx) |
87 | { |
88 | struct prog_test_ref_kfunc *p; |
89 | unsigned long sl = 0; |
90 | int sp = 0; |
91 | |
92 | p = bpf_kfunc_call_test_acquire(scalar_ptr: &sl); |
93 | if (!p) |
94 | return 0; |
95 | bpf_for_each_map_elem(&array_map, cb3, &sp, 0); |
96 | bpf_kfunc_call_test_release(p); |
97 | return 0; |
98 | } |
99 | |
100 | SEC("?tc" ) |
101 | int non_cb_transfer_ref(void *ctx) |
102 | { |
103 | struct prog_test_ref_kfunc *p; |
104 | unsigned long sl = 0; |
105 | |
106 | p = bpf_kfunc_call_test_acquire(scalar_ptr: &sl); |
107 | if (!p) |
108 | return 0; |
109 | cb1(NULL, NULL, NULL, &p); |
110 | bpf_kfunc_call_test_acquire(scalar_ptr: &sl); |
111 | return 0; |
112 | } |
113 | |
114 | char _license[] SEC("license" ) = "GPL" ; |
115 | |