Skip to content

Commit 08638cc

Browse files
kkdwvdNobody
authored andcommitted
selftests/bpf: Add C tests for kptr
This uses the __kptr* macros as well, and tries to test the stuff that is supposed to work, since we have negative tests in test_verifier suite. Also include some code to test map-in-map support, such that the inner_map_meta matches the map value of map added as element. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
1 parent 11c17fa commit 08638cc

File tree

2 files changed

+256
-0
lines changed

2 files changed

+256
-0
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <test_progs.h>
3+
4+
#include "map_kptr.skel.h"
5+
6+
void test_map_kptr(void)
7+
{
8+
struct map_kptr *skel;
9+
char buf[24];
10+
int key = 0;
11+
12+
skel = map_kptr__open_and_load();
13+
if (!ASSERT_OK_PTR(skel, "map_kptr__open_and_load"))
14+
return;
15+
ASSERT_OK(bpf_map_update_elem(bpf_map__fd(skel->maps.hash_map), &key, buf, 0),
16+
"bpf_map_update_elem hash_map");
17+
ASSERT_OK(bpf_map_update_elem(bpf_map__fd(skel->maps.hash_malloc_map), &key, buf, 0),
18+
"bpf_map_update_elem hash_malloc_map");
19+
map_kptr__destroy(skel);
20+
}
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <vmlinux.h>
3+
#include <bpf/bpf_tracing.h>
4+
#include <bpf/bpf_helpers.h>
5+
6+
struct map_value {
7+
struct prog_test_ref_kfunc __kptr *unref_ptr;
8+
struct prog_test_ref_kfunc __kptr_ref *ref_ptr;
9+
struct prog_test_ref_kfunc __kptr_percpu *percpu_ptr;
10+
struct prog_test_ref_kfunc __kptr_user *user_ptr;
11+
};
12+
13+
struct array_map {
14+
__uint(type, BPF_MAP_TYPE_ARRAY);
15+
__type(key, int);
16+
__type(value, struct map_value);
17+
__uint(max_entries, 1);
18+
} array_map SEC(".maps");
19+
20+
struct hash_map {
21+
__uint(type, BPF_MAP_TYPE_HASH);
22+
__uint(map_flags, BPF_F_NO_PREALLOC);
23+
__type(key, int);
24+
__type(value, struct map_value);
25+
__uint(max_entries, 1);
26+
} hash_map SEC(".maps");
27+
28+
struct hash_malloc_map {
29+
__uint(type, BPF_MAP_TYPE_HASH);
30+
__type(key, int);
31+
__type(value, struct map_value);
32+
__uint(max_entries, 1);
33+
__uint(map_flags, BPF_F_NO_PREALLOC);
34+
} hash_malloc_map SEC(".maps");
35+
36+
struct lru_hash_map {
37+
__uint(type, BPF_MAP_TYPE_LRU_HASH);
38+
__type(key, int);
39+
__type(value, struct map_value);
40+
__uint(max_entries, 1);
41+
} lru_hash_map SEC(".maps");
42+
43+
#define DEFINE_MAP_OF_MAP(map_type, inner_map_type, name) \
44+
struct { \
45+
__uint(type, map_type); \
46+
__uint(max_entries, 1); \
47+
__uint(key_size, sizeof(int)); \
48+
__uint(value_size, sizeof(int)); \
49+
__array(values, struct inner_map_type); \
50+
} name SEC(".maps") = { \
51+
.values = { [0] = &inner_map_type }, \
52+
}
53+
54+
DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_ARRAY_OF_MAPS, array_map, array_of_array_maps);
55+
DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_ARRAY_OF_MAPS, hash_map, array_of_hash_maps);
56+
DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_ARRAY_OF_MAPS, hash_malloc_map, array_of_hash_malloc_maps);
57+
DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_ARRAY_OF_MAPS, lru_hash_map, array_of_lru_hash_maps);
58+
DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_HASH_OF_MAPS, array_map, hash_of_array_maps);
59+
DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_HASH_OF_MAPS, hash_map, hash_of_hash_maps);
60+
DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_HASH_OF_MAPS, hash_malloc_map, hash_of_hash_malloc_maps);
61+
DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_HASH_OF_MAPS, lru_hash_map, hash_of_lru_hash_maps);
62+
63+
extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym;
64+
extern struct prog_test_ref_kfunc *
65+
bpf_kfunc_call_test_kptr_get(struct prog_test_ref_kfunc **p, int a, int b) __ksym;
66+
extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym;
67+
68+
static __always_inline
69+
void test_kptr_unref(struct map_value *v)
70+
{
71+
struct prog_test_ref_kfunc *p;
72+
73+
p = v->unref_ptr;
74+
/* store untrusted_ptr_or_null_ */
75+
v->unref_ptr = p;
76+
if (!p)
77+
return;
78+
if (p->a + p->b > 100)
79+
return;
80+
/* store untrusted_ptr_ */
81+
v->unref_ptr = p;
82+
/* store NULL */
83+
v->unref_ptr = NULL;
84+
}
85+
86+
static __always_inline
87+
void test_kptr_ref(struct map_value *v)
88+
{
89+
struct prog_test_ref_kfunc *p;
90+
91+
p = v->ref_ptr;
92+
/* store ptr_or_null_ */
93+
v->unref_ptr = p;
94+
if (!p)
95+
return;
96+
if (p->a + p->b > 100)
97+
return;
98+
/* store NULL */
99+
p = bpf_kptr_xchg(&v->ref_ptr, NULL);
100+
if (!p)
101+
return;
102+
if (p->a + p->b > 100) {
103+
bpf_kfunc_call_test_release(p);
104+
return;
105+
}
106+
/* store ptr_ */
107+
v->unref_ptr = p;
108+
bpf_kfunc_call_test_release(p);
109+
110+
p = bpf_kfunc_call_test_acquire(&(unsigned long){0});
111+
if (!p)
112+
return;
113+
/* store ptr_ */
114+
p = bpf_kptr_xchg(&v->ref_ptr, p);
115+
if (!p)
116+
return;
117+
if (p->a + p->b > 100) {
118+
bpf_kfunc_call_test_release(p);
119+
return;
120+
}
121+
bpf_kfunc_call_test_release(p);
122+
}
123+
124+
static __always_inline
125+
void test_kptr_percpu(struct map_value *v)
126+
{
127+
struct prog_test_ref_kfunc *p;
128+
129+
p = v->percpu_ptr;
130+
/* store percpu_ptr_or_null_ */
131+
v->percpu_ptr = p;
132+
if (!p)
133+
return;
134+
p = bpf_this_cpu_ptr(p);
135+
if (p->a + p->b > 100)
136+
return;
137+
/* store percpu_ptr_ */
138+
v->percpu_ptr = p;
139+
/* store NULL */
140+
v->percpu_ptr = NULL;
141+
}
142+
143+
static __always_inline
144+
void test_kptr_user(struct map_value *v)
145+
{
146+
struct prog_test_ref_kfunc *p;
147+
char buf[sizeof(*p)];
148+
149+
p = v->user_ptr;
150+
/* store user_ptr_or_null_ */
151+
v->user_ptr = p;
152+
if (!p)
153+
return;
154+
bpf_probe_read_user(buf, sizeof(buf), p);
155+
/* store user_ptr_ */
156+
v->user_ptr = p;
157+
/* store NULL */
158+
v->user_ptr = NULL;
159+
}
160+
161+
static __always_inline
162+
void test_kptr_get(struct map_value *v)
163+
{
164+
struct prog_test_ref_kfunc *p;
165+
166+
p = bpf_kfunc_call_test_kptr_get(&v->ref_ptr, 0, 0);
167+
if (!p)
168+
return;
169+
if (p->a + p->b > 100) {
170+
bpf_kfunc_call_test_release(p);
171+
return;
172+
}
173+
bpf_kfunc_call_test_release(p);
174+
}
175+
176+
static __always_inline
177+
void test_kptr(struct map_value *v)
178+
{
179+
test_kptr_unref(v);
180+
test_kptr_ref(v);
181+
test_kptr_percpu(v);
182+
test_kptr_user(v);
183+
test_kptr_get(v);
184+
}
185+
186+
SEC("tc")
187+
int test_map_kptr(struct __sk_buff *ctx)
188+
{
189+
void *maps[] = {
190+
&array_map,
191+
&hash_map,
192+
&hash_malloc_map,
193+
&lru_hash_map,
194+
};
195+
struct map_value *v;
196+
int i, key = 0;
197+
198+
for (i = 0; i < sizeof(maps) / sizeof(*maps); i++) {
199+
v = bpf_map_lookup_elem(&array_map, &key);
200+
if (!v)
201+
return 0;
202+
test_kptr(v);
203+
}
204+
return 0;
205+
}
206+
207+
SEC("tc")
208+
int test_map_in_map_kptr(struct __sk_buff *ctx)
209+
{
210+
void *map_of_maps[] = {
211+
&array_of_array_maps,
212+
&array_of_hash_maps,
213+
&array_of_hash_malloc_maps,
214+
&array_of_lru_hash_maps,
215+
&hash_of_array_maps,
216+
&hash_of_hash_maps,
217+
&hash_of_hash_malloc_maps,
218+
&hash_of_lru_hash_maps,
219+
};
220+
struct map_value *v;
221+
int i, key = 0;
222+
void *map;
223+
224+
for (i = 0; i < sizeof(map_of_maps) / sizeof(*map_of_maps); i++) {
225+
map = bpf_map_lookup_elem(&array_of_array_maps, &key);
226+
if (!map)
227+
return 0;
228+
v = bpf_map_lookup_elem(map, &key);
229+
if (!v)
230+
return 0;
231+
test_kptr(v);
232+
}
233+
return 0;
234+
}
235+
236+
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)