1 /*	$NetBSD: t_extmem.c,v 1.2 2017/01/13 21:30:42 christos Exp $ */
2 
3 /*-
4  * Copyright (c) 2014 Alexander Nasonov.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: t_extmem.c,v 1.2 2017/01/13 21:30:42 christos Exp $");
34 
35 #include <stdint.h>
36 #include <string.h>
37 
38 #define __BPF_PRIVATE
39 #include <net/bpf.h>
40 #include <net/bpfjit.h>
41 
42 #include "../../net/bpf/h_bpf.h"
43 
44 /* XXX: atf-c.h has collisions with mbuf */
45 #undef m_type
46 #undef m_data
47 #include <atf-c.h>
48 
49 #include "h_macros.h"
50 
51 static uint32_t retM(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
52 
53 static const bpf_copfunc_t copfuncs[] = {
54 	&retM
55 };
56 
57 static const bpf_ctx_t ctx = {
58 	.copfuncs = copfuncs,
59 	.nfuncs = sizeof(copfuncs) / sizeof(copfuncs[0]),
60 	.extwords = 4,
61 	.preinited = BPF_MEMWORD_INIT(0) | BPF_MEMWORD_INIT(3),
62 };
63 
64 static uint32_t
65 retM(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
66 {
67 
68 	return args->mem[(uintptr_t)args->arg];
69 }
70 
71 
72 ATF_TC(bpfjit_extmem_load_preinited);
73 ATF_TC_HEAD(bpfjit_extmem_load_preinited, tc)
74 {
75 	atf_tc_set_md_var(tc, "descr", "Test a load of external "
76 	    "pre-initialized memory");
77 }
78 
79 ATF_TC_BODY(bpfjit_extmem_load_preinited, tc)
80 {
81 	static struct bpf_insn insns[] = {
82 		BPF_STMT(BPF_LD+BPF_MEM, 3),
83 		BPF_STMT(BPF_RET+BPF_A, 0)
84 	};
85 
86 	bpfjit_func_t code;
87 	uint8_t pkt[1] = { 0 };
88 	uint32_t mem[ctx.extwords];
89 
90 	/* Pre-inited words. */
91 	mem[0] = 0;
92 	mem[3] = 3;
93 
94 	bpf_args_t args = {
95 		.pkt = pkt,
96 		.buflen = sizeof(pkt),
97 		.wirelen = sizeof(pkt),
98 		.mem = mem,
99 	};
100 
101 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
102 
103 	RZ(rump_init());
104 
105 	rump_schedule();
106 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
107 	rump_unschedule();
108 	ATF_REQUIRE(code != NULL);
109 
110 	ATF_CHECK(code(&ctx, &args) == 3);
111 
112 	rump_schedule();
113 	rumpns_bpfjit_free_code(code);
114 	rump_unschedule();
115 }
116 
117 ATF_TC(bpfjit_extmem_invalid_load);
118 ATF_TC_HEAD(bpfjit_extmem_invalid_load, tc)
119 {
120 	atf_tc_set_md_var(tc, "descr", "Test that out-of-range load "
121 	    "fails validation");
122 }
123 
124 ATF_TC_BODY(bpfjit_extmem_invalid_load, tc)
125 {
126 	static struct bpf_insn insns[] = {
127 		BPF_STMT(BPF_LD+BPF_MEM, 4),
128 		BPF_STMT(BPF_RET+BPF_A, 0)
129 	};
130 
131 	bpfjit_func_t code;
132 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
133 
134 	RZ(rump_init());
135 
136 	rump_schedule();
137 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
138 	rump_unschedule();
139 	ATF_CHECK(code == NULL);
140 }
141 
142 ATF_TC(bpfjit_extmem_store);
143 ATF_TC_HEAD(bpfjit_extmem_store, tc)
144 {
145 	atf_tc_set_md_var(tc, "descr", "Test stores to external memory");
146 }
147 
148 ATF_TC_BODY(bpfjit_extmem_store, tc)
149 {
150 	static struct bpf_insn insns[] = {
151 		BPF_STMT(BPF_LD+BPF_IMM, 1),        /* A <- 1     */
152 		BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 2), /* X <- 2     */
153 		BPF_STMT(BPF_ST, 1),                /* M[1] <- A  */
154 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
155 		BPF_STMT(BPF_STX, 2),               /* M[2] <- X  */
156 		BPF_STMT(BPF_ST, 3),                /* M[3] <- A  */
157 		BPF_STMT(BPF_RET+BPF_A, 0)          /* ret A      */
158 	};
159 
160 	bpfjit_func_t code;
161 	uint8_t pkt[1] = { 0 };
162 	uint32_t mem[ctx.extwords];
163 
164 	/* Pre-inited words. */
165 	mem[0] = 0;
166 	mem[3] = 7;
167 
168 	mem[1] = mem[2] = 0xdeadbeef;
169 
170 	bpf_args_t args = {
171 		.pkt = pkt,
172 		.buflen = sizeof(pkt),
173 		.wirelen = sizeof(pkt),
174 		.mem = mem,
175 	};
176 
177 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
178 
179 	RZ(rump_init());
180 
181 	rump_schedule();
182 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
183 	rump_unschedule();
184 	ATF_REQUIRE(code != NULL);
185 
186 	ATF_CHECK(code(&ctx, &args) == 3);
187 
188 	rump_schedule();
189 	rumpns_bpfjit_free_code(code);
190 	rump_unschedule();
191 
192 	ATF_CHECK(mem[0] == 0);
193 	ATF_CHECK(mem[1] == 1);
194 	ATF_CHECK(mem[2] == 2);
195 	ATF_CHECK(mem[3] == 3);
196 }
197 
198 ATF_TC(bpfjit_extmem_side_effect);
199 ATF_TC_HEAD(bpfjit_extmem_side_effect, tc)
200 {
201 	atf_tc_set_md_var(tc, "descr", "Test that ABC optimization doesn\'t "
202 	    "skip stores to external memory");
203 }
204 
205 ATF_TC_BODY(bpfjit_extmem_side_effect, tc)
206 {
207 	static struct bpf_insn insns[] = {
208 		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),  /* A <- P[0]  */
209 		BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 2), /* X <- 2     */
210 		BPF_STMT(BPF_ST, 1),                /* M[1] <- A  */
211 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
212 		BPF_STMT(BPF_STX, 2),               /* M[2] <- X  */
213 		BPF_STMT(BPF_ST, 3),                /* M[3] <- A  */
214 		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99), /* A <- P[99] */
215 		BPF_STMT(BPF_RET+BPF_A, 0)          /* ret A      */
216 	};
217 
218 	bpfjit_func_t code;
219 	uint8_t pkt[1] = { 1 };
220 	uint32_t mem[ctx.extwords];
221 
222 	/* Pre-inited words. */
223 	mem[0] = 0;
224 	mem[3] = 7;
225 
226 	mem[1] = mem[2] = 0xdeadbeef;
227 
228 	bpf_args_t args = {
229 		.pkt = pkt,
230 		.buflen = sizeof(pkt),
231 		.wirelen = sizeof(pkt),
232 		.mem = mem,
233 	};
234 
235 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
236 
237 	RZ(rump_init());
238 
239 	rump_schedule();
240 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
241 	rump_unschedule();
242 	ATF_REQUIRE(code != NULL);
243 
244 	ATF_CHECK(code(&ctx, &args) == 0);
245 
246 	rump_schedule();
247 	rumpns_bpfjit_free_code(code);
248 	rump_unschedule();
249 
250 	ATF_CHECK(mem[0] == 0);
251 	ATF_CHECK(mem[1] == 1);
252 	ATF_CHECK(mem[2] == 2);
253 	ATF_CHECK(mem[3] == 3);
254 }
255 
256 ATF_TC(bpfjit_extmem_invalid_store);
257 ATF_TC_HEAD(bpfjit_extmem_invalid_store, tc)
258 {
259 	atf_tc_set_md_var(tc, "descr", "Test that out-of-range store "
260 	    "fails validation");
261 }
262 
263 ATF_TC_BODY(bpfjit_extmem_invalid_store, tc)
264 {
265 	static struct bpf_insn insns[] = {
266 		BPF_STMT(BPF_ST, 4),
267 		BPF_STMT(BPF_RET+BPF_A, 0)
268 	};
269 
270 	bpfjit_func_t code;
271 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
272 
273 	RZ(rump_init());
274 
275 	rump_schedule();
276 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
277 	rump_unschedule();
278 	ATF_CHECK(code == NULL);
279 }
280 
281 ATF_TC(bpfjit_cop_ret_mem);
282 ATF_TC_HEAD(bpfjit_cop_ret_mem, tc)
283 {
284 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
285 	    "that returns a content of external memory word");
286 }
287 
288 ATF_TC_BODY(bpfjit_cop_ret_mem, tc)
289 {
290 	static struct bpf_insn insns[] = {
291 		BPF_STMT(BPF_LD+BPF_IMM, 13),
292 		BPF_STMT(BPF_ST, 2),
293 		BPF_STMT(BPF_LD+BPF_IMM, 137),
294 		BPF_STMT(BPF_ST, 1),
295 		BPF_STMT(BPF_MISC+BPF_COP, 0), // retM
296 		BPF_STMT(BPF_RET+BPF_A, 0)
297 	};
298 
299 	bpfjit_func_t code;
300 	uint8_t pkt[1] = { 0 };
301 	uint32_t mem[ctx.extwords];
302 	void *arg = (void*)(uintptr_t)2;
303 
304 	/* Pre-inited words. */
305 	mem[0] = 0;
306 	mem[3] = 3;
307 
308 	bpf_args_t args = {
309 		.pkt = pkt,
310 		.buflen = sizeof(pkt),
311 		.wirelen = sizeof(pkt),
312 		.arg = arg,
313 		.mem = mem,
314 	};
315 
316 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
317 
318 	RZ(rump_init());
319 
320 	rump_schedule();
321 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
322 	rump_unschedule();
323 	ATF_REQUIRE(code != NULL);
324 
325 	ATF_CHECK(code(&ctx, &args) == 13);
326 
327 	rump_schedule();
328 	rumpns_bpfjit_free_code(code);
329 	rump_unschedule();
330 }
331 
332 ATF_TC(bpfjit_cop_ret_preinited_mem);
333 ATF_TC_HEAD(bpfjit_cop_ret_preinited_mem, tc)
334 {
335 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function that "
336 	    "returns a content of external pre-initialized memory word");
337 }
338 
339 ATF_TC_BODY(bpfjit_cop_ret_preinited_mem, tc)
340 {
341 	static struct bpf_insn insns[] = {
342 		BPF_STMT(BPF_LD+BPF_IMM, 13),
343 		BPF_STMT(BPF_ST, 2),
344 		BPF_STMT(BPF_LD+BPF_IMM, 137),
345 		BPF_STMT(BPF_ST, 1),
346 		BPF_STMT(BPF_MISC+BPF_COP, 0), // retM
347 		BPF_STMT(BPF_RET+BPF_A, 0)
348 	};
349 
350 	bpfjit_func_t code;
351 	uint8_t pkt[1] = { 0 };
352 	uint32_t mem[ctx.extwords];
353 	void *arg = (void*)(uintptr_t)3;
354 
355 	/* Pre-inited words. */
356 	mem[0] = 0;
357 	mem[3] = 3;
358 
359 	bpf_args_t args = {
360 		.pkt = pkt,
361 		.buflen = sizeof(pkt),
362 		.wirelen = sizeof(pkt),
363 		.arg = arg,
364 		.mem = mem,
365 	};
366 
367 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
368 
369 	RZ(rump_init());
370 
371 	rump_schedule();
372 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
373 	rump_unschedule();
374 	ATF_REQUIRE(code != NULL);
375 
376 	ATF_CHECK(code(&ctx, &args) == 3);
377 
378 	rump_schedule();
379 	rumpns_bpfjit_free_code(code);
380 	rump_unschedule();
381 }
382 
383 ATF_TC(bpfjit_copx_ret_mem);
384 ATF_TC_HEAD(bpfjit_copx_ret_mem, tc)
385 {
386 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
387 	    "that returns a content of external memory word");
388 }
389 
390 ATF_TC_BODY(bpfjit_copx_ret_mem, tc)
391 {
392 	static struct bpf_insn insns[] = {
393 		BPF_STMT(BPF_LD+BPF_IMM, 13),
394 		BPF_STMT(BPF_ST, 2),
395 		BPF_STMT(BPF_LD+BPF_IMM, 137),
396 		BPF_STMT(BPF_ST, 1),
397 		BPF_STMT(BPF_LDX+BPF_IMM, 0), // retM
398 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
399 		BPF_STMT(BPF_RET+BPF_A, 0)
400 	};
401 
402 	bpfjit_func_t code;
403 	uint8_t pkt[1] = { 0 };
404 	uint32_t mem[ctx.extwords];
405 	void *arg = (void*)(uintptr_t)2;
406 
407 	/* Pre-inited words. */
408 	mem[0] = 0;
409 	mem[3] = 3;
410 
411 	bpf_args_t args = {
412 		.pkt = pkt,
413 		.buflen = sizeof(pkt),
414 		.wirelen = sizeof(pkt),
415 		.arg = arg,
416 		.mem = mem,
417 	};
418 
419 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
420 
421 	RZ(rump_init());
422 
423 	rump_schedule();
424 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
425 	rump_unschedule();
426 	ATF_REQUIRE(code != NULL);
427 
428 	ATF_CHECK(code(&ctx, &args) == 13);
429 
430 	rump_schedule();
431 	rumpns_bpfjit_free_code(code);
432 	rump_unschedule();
433 }
434 
435 ATF_TC(bpfjit_copx_ret_preinited_mem);
436 ATF_TC_HEAD(bpfjit_copx_ret_preinited_mem, tc)
437 {
438 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function that "
439 	    "returns a content of external pre-initialized memory word");
440 }
441 
442 ATF_TC_BODY(bpfjit_copx_ret_preinited_mem, tc)
443 {
444 	static struct bpf_insn insns[] = {
445 		BPF_STMT(BPF_LD+BPF_IMM, 13),
446 		BPF_STMT(BPF_ST, 2),
447 		BPF_STMT(BPF_LD+BPF_IMM, 137),
448 		BPF_STMT(BPF_ST, 1),
449 		BPF_STMT(BPF_LDX+BPF_IMM, 0), // retM
450 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
451 		BPF_STMT(BPF_RET+BPF_A, 0)
452 	};
453 
454 	bpfjit_func_t code;
455 	uint8_t pkt[1] = { 0 };
456 	uint32_t mem[ctx.extwords];
457 	void *arg = (void*)(uintptr_t)3;
458 
459 	/* Pre-inited words. */
460 	mem[0] = 0;
461 	mem[3] = 3;
462 
463 	bpf_args_t args = {
464 		.pkt = pkt,
465 		.buflen = sizeof(pkt),
466 		.wirelen = sizeof(pkt),
467 		.arg = arg,
468 		.mem = mem,
469 	};
470 
471 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
472 
473 	RZ(rump_init());
474 
475 	rump_schedule();
476 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
477 	rump_unschedule();
478 	ATF_REQUIRE(code != NULL);
479 
480 	ATF_CHECK(code(&ctx, &args) == 3);
481 
482 	rump_schedule();
483 	rumpns_bpfjit_free_code(code);
484 	rump_unschedule();
485 }
486 
487 ATF_TP_ADD_TCS(tp)
488 {
489 
490 	/*
491 	 * For every new test please also add a similar test
492 	 * to ../../lib/libbpfjit/t_extmem.c
493 	 */
494 	//ATF_TP_ADD_TC(tp, bpfjit_extmem_load_default);
495 	ATF_TP_ADD_TC(tp, bpfjit_extmem_load_preinited);
496 	ATF_TP_ADD_TC(tp, bpfjit_extmem_invalid_load);
497 	ATF_TP_ADD_TC(tp, bpfjit_extmem_store);
498 	ATF_TP_ADD_TC(tp, bpfjit_extmem_side_effect);
499 	ATF_TP_ADD_TC(tp, bpfjit_extmem_invalid_store);
500 	ATF_TP_ADD_TC(tp, bpfjit_cop_ret_mem);
501 	ATF_TP_ADD_TC(tp, bpfjit_cop_ret_preinited_mem);
502 	ATF_TP_ADD_TC(tp, bpfjit_copx_ret_mem);
503 	ATF_TP_ADD_TC(tp, bpfjit_copx_ret_preinited_mem);
504 
505 	return atf_no_error();
506 }
507