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
retM(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)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);
ATF_TC_HEAD(bpfjit_extmem_load_preinited,tc)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
ATF_TC_BODY(bpfjit_extmem_load_preinited,tc)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);
ATF_TC_HEAD(bpfjit_extmem_invalid_load,tc)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
ATF_TC_BODY(bpfjit_extmem_invalid_load,tc)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);
ATF_TC_HEAD(bpfjit_extmem_store,tc)143 ATF_TC_HEAD(bpfjit_extmem_store, tc)
144 {
145 atf_tc_set_md_var(tc, "descr", "Test stores to external memory");
146 }
147
ATF_TC_BODY(bpfjit_extmem_store,tc)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);
ATF_TC_HEAD(bpfjit_extmem_side_effect,tc)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
ATF_TC_BODY(bpfjit_extmem_side_effect,tc)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);
ATF_TC_HEAD(bpfjit_extmem_invalid_store,tc)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
ATF_TC_BODY(bpfjit_extmem_invalid_store,tc)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);
ATF_TC_HEAD(bpfjit_cop_ret_mem,tc)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
ATF_TC_BODY(bpfjit_cop_ret_mem,tc)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);
ATF_TC_HEAD(bpfjit_cop_ret_preinited_mem,tc)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
ATF_TC_BODY(bpfjit_cop_ret_preinited_mem,tc)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);
ATF_TC_HEAD(bpfjit_copx_ret_mem,tc)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
ATF_TC_BODY(bpfjit_copx_ret_mem,tc)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);
ATF_TC_HEAD(bpfjit_copx_ret_preinited_mem,tc)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
ATF_TC_BODY(bpfjit_copx_ret_preinited_mem,tc)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
ATF_TP_ADD_TCS(tp)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