Skip to content

Commit 47f73da

Browse files
joannekoongNobody
authored and
Nobody
committed
bpf: Dynptr tests
This patch adds tests for dynptrs. These include scenarios that the verifier needs to reject, as well as some successful use cases of dynptrs that should pass. Some of the failure scenarios include checking against invalid bpf_frees, invalid writes, invalid reads, and invalid ringbuf API usages. Signed-off-by: Joanne Koong <[email protected]>
1 parent 9991018 commit 47f73da

File tree

3 files changed

+977
-0
lines changed

3 files changed

+977
-0
lines changed
Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2022 Facebook */
3+
4+
#include <test_progs.h>
5+
#include "dynptr_fail.skel.h"
6+
#include "dynptr_success.skel.h"
7+
8+
size_t log_buf_sz = 1024 * 1024;
9+
10+
enum fail_case {
11+
MISSING_FREE,
12+
MISSING_FREE_CALLBACK,
13+
INVALID_FREE1,
14+
INVALID_FREE2,
15+
USE_AFTER_FREE,
16+
MALLOC_TWICE,
17+
INVALID_MAP_CALL1,
18+
INVALID_MAP_CALL2,
19+
RINGBUF_INVALID_ACCESS,
20+
RINGBUF_INVALID_API,
21+
RINGBUF_OUT_OF_BOUNDS,
22+
DATA_SLICE_OUT_OF_BOUNDS,
23+
DATA_SLICE_USE_AFTER_FREE,
24+
INVALID_HELPER1,
25+
INVALID_HELPER2,
26+
INVALID_WRITE1,
27+
INVALID_WRITE2,
28+
INVALID_WRITE3,
29+
INVALID_WRITE4,
30+
INVALID_READ1,
31+
INVALID_READ2,
32+
INVALID_READ3,
33+
INVALID_OFFSET,
34+
GLOBAL,
35+
FREE_TWICE,
36+
FREE_TWICE_CALLBACK,
37+
};
38+
39+
static void verify_fail(enum fail_case fail, char *obj_log_buf, char *err_msg)
40+
{
41+
LIBBPF_OPTS(bpf_object_open_opts, opts);
42+
struct bpf_program *prog;
43+
struct dynptr_fail *skel;
44+
int err;
45+
46+
opts.kernel_log_buf = obj_log_buf;
47+
opts.kernel_log_size = log_buf_sz;
48+
opts.kernel_log_level = 1;
49+
50+
skel = dynptr_fail__open_opts(&opts);
51+
if (!ASSERT_OK_PTR(skel, "skel_open"))
52+
return;
53+
54+
bpf_object__for_each_program(prog, skel->obj)
55+
bpf_program__set_autoload(prog, false);
56+
57+
/* these programs should all be rejected by the verifier */
58+
switch (fail) {
59+
case MISSING_FREE:
60+
prog = skel->progs.missing_free;
61+
break;
62+
case MISSING_FREE_CALLBACK:
63+
prog = skel->progs.missing_free_callback;
64+
break;
65+
case INVALID_FREE1:
66+
prog = skel->progs.invalid_free1;
67+
break;
68+
case INVALID_FREE2:
69+
prog = skel->progs.invalid_free2;
70+
break;
71+
case USE_AFTER_FREE:
72+
prog = skel->progs.use_after_free;
73+
break;
74+
case MALLOC_TWICE:
75+
prog = skel->progs.malloc_twice;
76+
break;
77+
case INVALID_MAP_CALL1:
78+
prog = skel->progs.invalid_map_call1;
79+
break;
80+
case INVALID_MAP_CALL2:
81+
prog = skel->progs.invalid_map_call2;
82+
break;
83+
case RINGBUF_INVALID_ACCESS:
84+
prog = skel->progs.ringbuf_invalid_access;
85+
break;
86+
case RINGBUF_INVALID_API:
87+
prog = skel->progs.ringbuf_invalid_api;
88+
break;
89+
case RINGBUF_OUT_OF_BOUNDS:
90+
prog = skel->progs.ringbuf_out_of_bounds;
91+
break;
92+
case DATA_SLICE_OUT_OF_BOUNDS:
93+
prog = skel->progs.data_slice_out_of_bounds;
94+
break;
95+
case DATA_SLICE_USE_AFTER_FREE:
96+
prog = skel->progs.data_slice_use_after_free;
97+
break;
98+
case INVALID_HELPER1:
99+
prog = skel->progs.invalid_helper1;
100+
break;
101+
case INVALID_HELPER2:
102+
prog = skel->progs.invalid_helper2;
103+
break;
104+
case INVALID_WRITE1:
105+
prog = skel->progs.invalid_write1;
106+
break;
107+
case INVALID_WRITE2:
108+
prog = skel->progs.invalid_write2;
109+
break;
110+
case INVALID_WRITE3:
111+
prog = skel->progs.invalid_write3;
112+
break;
113+
case INVALID_WRITE4:
114+
prog = skel->progs.invalid_write4;
115+
break;
116+
case INVALID_READ1:
117+
prog = skel->progs.invalid_read1;
118+
break;
119+
case INVALID_READ2:
120+
prog = skel->progs.invalid_read2;
121+
break;
122+
case INVALID_READ3:
123+
prog = skel->progs.invalid_read3;
124+
break;
125+
case INVALID_OFFSET:
126+
prog = skel->progs.invalid_offset;
127+
break;
128+
case GLOBAL:
129+
prog = skel->progs.global;
130+
break;
131+
case FREE_TWICE:
132+
prog = skel->progs.free_twice;
133+
break;
134+
case FREE_TWICE_CALLBACK:
135+
prog = skel->progs.free_twice_callback;
136+
break;
137+
default:
138+
fprintf(stderr, "unknown fail_case\n");
139+
return;
140+
}
141+
142+
bpf_program__set_autoload(prog, true);
143+
144+
err = dynptr_fail__load(skel);
145+
146+
ASSERT_OK_PTR(strstr(obj_log_buf, err_msg), "err_msg not found");
147+
148+
ASSERT_ERR(err, "unexpected load success");
149+
150+
dynptr_fail__destroy(skel);
151+
}
152+
153+
static void run_prog(struct dynptr_success *skel, struct bpf_program *prog)
154+
{
155+
struct bpf_link *link;
156+
157+
link = bpf_program__attach(prog);
158+
if (!ASSERT_OK_PTR(link, "bpf program attach"))
159+
return;
160+
161+
usleep(1);
162+
163+
ASSERT_EQ(skel->bss->err, 0, "err");
164+
165+
bpf_link__destroy(link);
166+
}
167+
168+
static void verify_success(void)
169+
{
170+
struct dynptr_success *skel;
171+
172+
skel = dynptr_success__open();
173+
174+
skel->bss->pid = getpid();
175+
176+
dynptr_success__load(skel);
177+
if (!ASSERT_OK_PTR(skel, "dynptr__open_and_load"))
178+
return;
179+
180+
run_prog(skel, skel->progs.prog_success);
181+
run_prog(skel, skel->progs.prog_success_data_slice);
182+
run_prog(skel, skel->progs.prog_success_ringbuf);
183+
184+
dynptr_success__destroy(skel);
185+
}
186+
187+
void test_dynptr(void)
188+
{
189+
char *obj_log_buf;
190+
191+
obj_log_buf = malloc(3 * log_buf_sz);
192+
if (!ASSERT_OK_PTR(obj_log_buf, "obj_log_buf"))
193+
return;
194+
obj_log_buf[0] = '\0';
195+
196+
if (test__start_subtest("missing_free"))
197+
verify_fail(MISSING_FREE, obj_log_buf,
198+
"spi=0 is an unreleased dynptr");
199+
200+
if (test__start_subtest("missing_free_callback"))
201+
verify_fail(MISSING_FREE_CALLBACK, obj_log_buf,
202+
"spi=0 is an unreleased dynptr");
203+
204+
if (test__start_subtest("invalid_free1"))
205+
verify_fail(INVALID_FREE1, obj_log_buf,
206+
"arg #1 is an unacquired reference and hence cannot be released");
207+
208+
if (test__start_subtest("invalid_free2"))
209+
verify_fail(INVALID_FREE2, obj_log_buf, "type=alloc_mem_or_null expected=fp");
210+
211+
if (test__start_subtest("use_after_free"))
212+
verify_fail(USE_AFTER_FREE, obj_log_buf,
213+
"Expected an initialized dynptr as arg #3");
214+
215+
if (test__start_subtest("malloc_twice"))
216+
verify_fail(MALLOC_TWICE, obj_log_buf,
217+
"Arg #2 dynptr cannot be an initialized dynptr");
218+
219+
if (test__start_subtest("invalid_map_call1"))
220+
verify_fail(INVALID_MAP_CALL1, obj_log_buf,
221+
"invalid indirect read from stack");
222+
223+
if (test__start_subtest("invalid_map_call2"))
224+
verify_fail(INVALID_MAP_CALL2, obj_log_buf,
225+
"invalid indirect read from stack");
226+
227+
if (test__start_subtest("invalid_helper1"))
228+
verify_fail(INVALID_HELPER1, obj_log_buf,
229+
"invalid indirect read from stack");
230+
231+
if (test__start_subtest("ringbuf_invalid_access"))
232+
verify_fail(RINGBUF_INVALID_ACCESS, obj_log_buf,
233+
"invalid mem access 'scalar'");
234+
235+
if (test__start_subtest("ringbuf_invalid_api"))
236+
verify_fail(RINGBUF_INVALID_API, obj_log_buf,
237+
"func bpf_ringbuf_submit#132 reference has not been acquired before");
238+
239+
if (test__start_subtest("ringbuf_out_of_bounds"))
240+
verify_fail(RINGBUF_OUT_OF_BOUNDS, obj_log_buf,
241+
"value is outside of the allowed memory range");
242+
243+
if (test__start_subtest("data_slice_out_of_bounds"))
244+
verify_fail(DATA_SLICE_OUT_OF_BOUNDS, obj_log_buf,
245+
"value is outside of the allowed memory range");
246+
247+
if (test__start_subtest("data_slice_use_after_free"))
248+
verify_fail(DATA_SLICE_USE_AFTER_FREE, obj_log_buf,
249+
"invalid mem access 'scalar'");
250+
251+
if (test__start_subtest("invalid_helper2"))
252+
verify_fail(INVALID_HELPER2, obj_log_buf,
253+
"Expected an initialized dynptr as arg #3");
254+
255+
if (test__start_subtest("invalid_write1"))
256+
verify_fail(INVALID_WRITE1, obj_log_buf,
257+
"direct write into dynptr is not permitted");
258+
259+
if (test__start_subtest("invalid_write2"))
260+
verify_fail(INVALID_WRITE2, obj_log_buf,
261+
"direct write into dynptr is not permitted");
262+
263+
if (test__start_subtest("invalid_write3"))
264+
verify_fail(INVALID_WRITE3, obj_log_buf,
265+
"direct write into dynptr is not permitted");
266+
267+
if (test__start_subtest("invalid_write4"))
268+
verify_fail(INVALID_WRITE4, obj_log_buf,
269+
"direct write into dynptr is not permitted");
270+
271+
if (test__start_subtest("invalid_read1"))
272+
verify_fail(INVALID_READ1, obj_log_buf,
273+
"invalid read from stack");
274+
275+
if (test__start_subtest("invalid_read2"))
276+
verify_fail(INVALID_READ2, obj_log_buf,
277+
"Expected an initialized dynptr as arg #3");
278+
279+
if (test__start_subtest("invalid_read3"))
280+
verify_fail(INVALID_READ3, obj_log_buf,
281+
"invalid read from stack");
282+
283+
if (test__start_subtest("invalid_offset"))
284+
verify_fail(INVALID_OFFSET, obj_log_buf,
285+
"invalid indirect access to stack");
286+
287+
if (test__start_subtest("global"))
288+
verify_fail(GLOBAL, obj_log_buf,
289+
"R2 type=map_value expected=fp");
290+
291+
if (test__start_subtest("free_twice"))
292+
verify_fail(FREE_TWICE, obj_log_buf,
293+
"arg #1 is an unacquired reference and hence cannot be released");
294+
295+
if (test__start_subtest("free_twice_callback"))
296+
verify_fail(FREE_TWICE_CALLBACK, obj_log_buf,
297+
"arg #1 is an unacquired reference and hence cannot be released");
298+
299+
if (test__start_subtest("success"))
300+
verify_success();
301+
302+
free(obj_log_buf);
303+
}

0 commit comments

Comments
 (0)