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