1 /*
2 * Check bpf syscall decoding.
3 *
4 * Copyright (c) 2015-2017 Dmitry V. Levin <ldv@altlinux.org>
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 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "tests.h"
31 #include <asm/unistd.h>
32
33 #if defined __NR_bpf \
34 && (defined HAVE_UNION_BPF_ATTR_ATTACH_FLAGS \
35 || defined HAVE_UNION_BPF_ATTR_BPF_FD \
36 || defined HAVE_UNION_BPF_ATTR_FLAGS \
37 || defined HAVE_UNION_BPF_ATTR_INFO_INFO \
38 || defined HAVE_UNION_BPF_ATTR_NEXT_ID \
39 || defined HAVE_UNION_BPF_ATTR_NUMA_NODE \
40 || defined HAVE_UNION_BPF_ATTR_PROG_FLAGS \
41 || defined HAVE_UNION_BPF_ATTR_TEST_DURATION)
42
43 # include <stddef.h>
44 # include <stdio.h>
45 # include <stdint.h>
46 # include <string.h>
47 # include <unistd.h>
48 # include <linux/bpf.h>
49 # include "print_fields.h"
50
51 static const kernel_ulong_t long_bits = (kernel_ulong_t) 0xfacefeed00000000ULL;
52 static const char *errstr;
53 static unsigned int sizeof_attr = sizeof(union bpf_attr);
54 static unsigned int page_size;
55 static unsigned long end_of_page;
56
57 static long
sys_bpf(kernel_ulong_t cmd,kernel_ulong_t attr,kernel_ulong_t size)58 sys_bpf(kernel_ulong_t cmd, kernel_ulong_t attr, kernel_ulong_t size)
59 {
60 long rc = syscall(__NR_bpf, cmd, attr, size);
61 errstr = sprintrc(rc);
62 return rc;
63 }
64
65 # if VERBOSE
66 # define print_extra_data(addr_, size_) print_quoted_hex((addr_), (size_))
67 # else
68 # define print_extra_data(addr_, size_) printf("...")
69 #endif
70
71 # define TEST_BPF_(cmd_, cmd_str_, \
72 init_first_, print_first_, \
73 init_attr_, print_attr_) \
74 do { \
75 /* zero addr */ \
76 sys_bpf(cmd_, 0, long_bits | sizeof(union bpf_attr)); \
77 printf("bpf(%s, NULL, %u) = %s\n", \
78 cmd_str_, sizeof_attr, errstr); \
79 \
80 /* zero size */ \
81 unsigned long addr = end_of_page - sizeof_attr; \
82 sys_bpf(cmd_, addr, long_bits); \
83 printf("bpf(%s, %#lx, 0) = %s\n", \
84 cmd_str_, addr, errstr); \
85 \
86 /* the first field only */ \
87 unsigned int offset = init_first_(end_of_page); \
88 addr = end_of_page - offset; \
89 sys_bpf(cmd_, addr, offset); \
90 printf("bpf(%s, {", cmd_str_); \
91 print_first_(addr); \
92 printf("}, %u) = %s\n", offset, errstr); \
93 \
94 /* efault after the first field */ \
95 sys_bpf(cmd_, addr, offset + 1); \
96 printf("bpf(%s, %#lx, %u) = %s\n", \
97 cmd_str_, addr, offset + 1, errstr); \
98 \
99 /* the relevant part of union bpf_attr */ \
100 offset = init_attr_(end_of_page); \
101 addr = end_of_page - offset; \
102 sys_bpf(cmd_, addr, offset); \
103 printf("bpf(%s, {", cmd_str_); \
104 print_attr_(addr); \
105 printf("}, %u) = %s\n", offset, errstr); \
106 \
107 /* short read of the relevant part of union bpf_attr */ \
108 sys_bpf(cmd_, addr + 1, offset); \
109 printf("bpf(%s, %#lx, %u) = %s\n", \
110 cmd_str_, addr + 1, offset, errstr); \
111 \
112 if (offset < sizeof_attr) { \
113 /* short read of the whole union bpf_attr */ \
114 memmove((void *) end_of_page - sizeof_attr + 1, \
115 (void *) addr, offset); \
116 addr = end_of_page - sizeof_attr + 1; \
117 memset((void *) addr + offset, 0, \
118 sizeof_attr - offset - 1); \
119 sys_bpf(cmd_, addr, sizeof_attr); \
120 printf("bpf(%s, %#lx, %u) = %s\n", \
121 cmd_str_, addr, sizeof_attr, errstr); \
122 \
123 /* the whole union bpf_attr */ \
124 memmove((void *) end_of_page - sizeof_attr, \
125 (void *) addr, offset); \
126 addr = end_of_page - sizeof_attr; \
127 memset((void *) addr + offset, 0, \
128 sizeof_attr - offset); \
129 sys_bpf(cmd_, addr, sizeof_attr); \
130 printf("bpf(%s, {", cmd_str_); \
131 print_attr_(addr); \
132 printf("}, %u) = %s\n", sizeof_attr, errstr); \
133 \
134 /* non-zero bytes after the relevant part */ \
135 fill_memory_ex((void *) addr + offset, \
136 sizeof_attr - offset, '0', 10); \
137 sys_bpf(cmd_, addr, sizeof_attr); \
138 printf("bpf(%s, {", cmd_str_); \
139 print_attr_(addr); \
140 printf(", "); \
141 print_extra_data((void *) addr + offset, \
142 sizeof_attr - offset); \
143 printf("}, %u) = %s\n", sizeof_attr, errstr); \
144 } \
145 \
146 /* short read of the whole page */ \
147 memmove((void *) end_of_page - page_size + 1, \
148 (void *) addr, offset); \
149 addr = end_of_page - page_size + 1; \
150 memset((void *) addr + offset, 0, \
151 page_size - offset - 1); \
152 sys_bpf(cmd_, addr, page_size); \
153 printf("bpf(%s, %#lx, %u) = %s\n", \
154 cmd_str_, addr, page_size, errstr); \
155 \
156 /* the whole page */ \
157 memmove((void *) end_of_page - page_size, \
158 (void *) addr, offset); \
159 addr = end_of_page - page_size; \
160 memset((void *) addr + offset, 0, page_size - offset); \
161 sys_bpf(cmd_, addr, page_size); \
162 printf("bpf(%s, {", cmd_str_); \
163 print_attr_(addr); \
164 printf("}, %u) = %s\n", page_size, errstr); \
165 \
166 /* non-zero bytes after the whole union bpf_attr */ \
167 fill_memory_ex((void *) addr + offset, \
168 page_size - offset, '0', 10); \
169 sys_bpf(cmd_, addr, page_size); \
170 printf("bpf(%s, {", cmd_str_); \
171 print_attr_(addr); \
172 printf(", "); \
173 print_extra_data((void *) addr + offset, \
174 page_size - offset); \
175 printf("}, %u) = %s\n", page_size, errstr); \
176 \
177 /* more than a page */ \
178 sys_bpf(cmd_, addr, page_size + 1); \
179 printf("bpf(%s, %#lx, %u) = %s\n", \
180 cmd_str_, addr, page_size + 1, errstr); \
181 } while (0) \
182 /* End of TEST_BPF_ definition. */
183
184 # define TEST_BPF(cmd_) \
185 TEST_BPF_((cmd_), #cmd_, \
186 init_ ## cmd_ ## _first, print_ ## cmd_ ## _first, \
187 init_ ## cmd_ ## _attr, print_ ## cmd_ ## _attr) \
188 /* End of TEST_BPF definition. */
189
190 #define DEF_BPF_INIT_FIRST(cmd_, field_, value_) \
191 static unsigned int \
192 init_ ## cmd_ ## _first(const unsigned long eop) \
193 { \
194 static const union bpf_attr attr = { .field_ = value_ };\
195 static const unsigned int offset = sizeof(attr.field_); \
196 const unsigned long addr = eop - offset; \
197 \
198 memcpy((void *) addr, &attr.field_, offset); \
199 return offset; \
200 } \
201 /* End of DEF_INIT_FIRST definition. */
202
203 # ifdef HAVE_UNION_BPF_ATTR_NUMA_NODE
204
205 DEF_BPF_INIT_FIRST(BPF_MAP_CREATE, map_type, 2)
206
207 static void
print_BPF_MAP_CREATE_first(const unsigned long addr)208 print_BPF_MAP_CREATE_first(const unsigned long addr)
209 {
210 printf("map_type=BPF_MAP_TYPE_ARRAY, key_size=0, value_size=0"
211 ", max_entries=0, map_flags=0, inner_map_fd=0");
212 }
213
214 static unsigned int
init_BPF_MAP_CREATE_attr(const unsigned long eop)215 init_BPF_MAP_CREATE_attr(const unsigned long eop)
216 {
217 static const union bpf_attr attr = {
218 .map_type = 1,
219 .key_size = 4,
220 .value_size = 8,
221 .max_entries = 256,
222 .map_flags = 7,
223 .inner_map_fd = -1,
224 .numa_node = 42
225 };
226 static const unsigned int offset =
227 offsetofend(union bpf_attr, numa_node);
228 const unsigned long addr = eop - offset;
229
230 memcpy((void *) addr, &attr, offset);
231 return offset;
232 }
233
234 static void
print_BPF_MAP_CREATE_attr(const unsigned long addr)235 print_BPF_MAP_CREATE_attr(const unsigned long addr)
236 {
237 printf("map_type=BPF_MAP_TYPE_HASH, key_size=4"
238 ", value_size=8, max_entries=256"
239 ", map_flags=BPF_F_NO_PREALLOC|BPF_F_NO_COMMON_LRU"
240 "|BPF_F_NUMA_NODE, inner_map_fd=-1, numa_node=42");
241 }
242
243 # endif /* HAVE_UNION_BPF_ATTR_NUMA_NODE */
244
245 # ifdef HAVE_UNION_BPF_ATTR_FLAGS
246
247 DEF_BPF_INIT_FIRST(BPF_MAP_LOOKUP_ELEM, map_fd, -1)
248
249 static void
print_BPF_MAP_LOOKUP_ELEM_first(const unsigned long addr)250 print_BPF_MAP_LOOKUP_ELEM_first(const unsigned long addr)
251 {
252 printf("map_fd=-1, key=0, value=0");
253 }
254
255 static unsigned int
init_BPF_MAP_LOOKUP_ELEM_attr(const unsigned long eop)256 init_BPF_MAP_LOOKUP_ELEM_attr(const unsigned long eop)
257 {
258 static const union bpf_attr attr = {
259 .map_fd = -1,
260 .key = 0xdeadbeef,
261 .value = 0xbadc0ded
262 };
263 static const unsigned int offset =
264 offsetofend(union bpf_attr, value);
265 const unsigned long addr = eop - offset;
266
267 memcpy((void *) addr, &attr, offset);
268 return offset;
269 }
270
271 static void
print_BPF_MAP_LOOKUP_ELEM_attr(const unsigned long addr)272 print_BPF_MAP_LOOKUP_ELEM_attr(const unsigned long addr)
273 {
274 printf("map_fd=-1, key=0xdeadbeef, value=0xbadc0ded");
275 }
276
277 # define init_BPF_MAP_UPDATE_ELEM_first init_BPF_MAP_LOOKUP_ELEM_first
278
279 static void
print_BPF_MAP_UPDATE_ELEM_first(const unsigned long addr)280 print_BPF_MAP_UPDATE_ELEM_first(const unsigned long addr)
281 {
282 printf("map_fd=-1, key=0, value=0, flags=BPF_ANY");
283 }
284
285 static unsigned int
init_BPF_MAP_UPDATE_ELEM_attr(const unsigned long eop)286 init_BPF_MAP_UPDATE_ELEM_attr(const unsigned long eop)
287 {
288 static const union bpf_attr attr = {
289 .map_fd = -1,
290 .key = 0xdeadbeef,
291 .value = 0xbadc0ded,
292 .flags = 2
293 };
294 static const unsigned int offset =
295 offsetofend(union bpf_attr, flags);
296 const unsigned long addr = eop - offset;
297
298 memcpy((void *) addr, &attr, offset);
299 return offset;
300 }
301
302 static void
print_BPF_MAP_UPDATE_ELEM_attr(const unsigned long addr)303 print_BPF_MAP_UPDATE_ELEM_attr(const unsigned long addr)
304 {
305 printf("map_fd=-1, key=0xdeadbeef, value=0xbadc0ded, flags=BPF_EXIST");
306 }
307
308 # define init_BPF_MAP_DELETE_ELEM_first init_BPF_MAP_LOOKUP_ELEM_first
309
310 static void
print_BPF_MAP_DELETE_ELEM_first(const unsigned long addr)311 print_BPF_MAP_DELETE_ELEM_first(const unsigned long addr)
312 {
313 printf("map_fd=-1, key=0");
314 }
315
316 static unsigned int
init_BPF_MAP_DELETE_ELEM_attr(const unsigned long eop)317 init_BPF_MAP_DELETE_ELEM_attr(const unsigned long eop)
318 {
319 static const union bpf_attr attr = {
320 .map_fd = -1,
321 .key = 0xdeadbeef
322 };
323 static const unsigned int offset =
324 offsetofend(union bpf_attr, key);
325 const unsigned long addr = eop - offset;
326
327 memcpy((void *) addr, &attr, offset);
328 return offset;
329 }
330
331 static void
print_BPF_MAP_DELETE_ELEM_attr(const unsigned long addr)332 print_BPF_MAP_DELETE_ELEM_attr(const unsigned long addr)
333 {
334 printf("map_fd=-1, key=0xdeadbeef");
335 }
336
337 # define init_BPF_MAP_GET_NEXT_KEY_first init_BPF_MAP_LOOKUP_ELEM_first
338
339 static void
print_BPF_MAP_GET_NEXT_KEY_first(const unsigned long addr)340 print_BPF_MAP_GET_NEXT_KEY_first(const unsigned long addr)
341 {
342 printf("map_fd=-1, key=0, next_key=0");
343 }
344
345 static unsigned int
init_BPF_MAP_GET_NEXT_KEY_attr(const unsigned long eop)346 init_BPF_MAP_GET_NEXT_KEY_attr(const unsigned long eop)
347 {
348 static const union bpf_attr attr = {
349 .map_fd = -1,
350 .key = 0xdeadbeef,
351 .next_key = 0xbadc0ded
352 };
353 static const unsigned int offset =
354 offsetofend(union bpf_attr, next_key);
355 const unsigned long addr = eop - offset;
356
357 memcpy((void *) addr, &attr, offset);
358 return offset;
359 }
360
361 static void
print_BPF_MAP_GET_NEXT_KEY_attr(const unsigned long addr)362 print_BPF_MAP_GET_NEXT_KEY_attr(const unsigned long addr)
363 {
364 printf("map_fd=-1, key=0xdeadbeef, next_key=0xbadc0ded");
365 }
366
367 # endif /* HAVE_UNION_BPF_ATTR_FLAGS */
368
369 # ifdef HAVE_UNION_BPF_ATTR_PROG_FLAGS
370
371 DEF_BPF_INIT_FIRST(BPF_PROG_LOAD, prog_type, 1)
372
373 static void
print_BPF_PROG_LOAD_first(const unsigned long addr)374 print_BPF_PROG_LOAD_first(const unsigned long addr)
375 {
376
377 printf("prog_type=BPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=0, insns=0"
378 ", license=NULL, log_level=0, log_size=0, log_buf=0"
379 ", kern_version=0, prog_flags=0");
380 }
381
382 static const struct bpf_insn insns[] = {
383 { .code = BPF_JMP | BPF_EXIT }
384 };
385 static char log_buf[4096];
386
387 static unsigned int
init_BPF_PROG_LOAD_attr(const unsigned long eop)388 init_BPF_PROG_LOAD_attr(const unsigned long eop)
389 {
390 const union bpf_attr attr = {
391 .prog_type = 1,
392 .insn_cnt = ARRAY_SIZE(insns),
393 .insns = (uintptr_t) insns,
394 .license = (uintptr_t) "GPL",
395 .log_level = 42,
396 .log_size = sizeof(log_buf),
397 .log_buf = (uintptr_t) log_buf,
398 .kern_version = 0xcafef00d,
399 .prog_flags = 1
400 };
401 static const unsigned int offset =
402 offsetofend(union bpf_attr, prog_flags);
403 const unsigned long addr = eop - offset;
404
405 memcpy((void *) addr, &attr, offset);
406 return offset;
407 }
408
409 static void
print_BPF_PROG_LOAD_attr(const unsigned long addr)410 print_BPF_PROG_LOAD_attr(const unsigned long addr)
411 {
412 printf("prog_type=BPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=%u, insns=%p"
413 ", license=\"GPL\", log_level=42, log_size=4096, log_buf=%p"
414 ", kern_version=%u, prog_flags=BPF_F_STRICT_ALIGNMENT",
415 (unsigned int) ARRAY_SIZE(insns), insns,
416 log_buf, 0xcafef00d);
417 }
418
419 # endif /* HAVE_UNION_BPF_ATTR_PROG_FLAGS */
420
421 /*
422 * bpf() syscall and its first six commands were introduced in Linux kernel
423 * 3.18. Some additional commands were added afterwards, so we need to take
424 * precautions to make sure the tests compile.
425 *
426 * BPF_OBJ_PIN and BPF_OBJ_GET commands appear in kernel 4.4.
427 */
428 # ifdef HAVE_UNION_BPF_ATTR_BPF_FD
429
430 DEF_BPF_INIT_FIRST(BPF_OBJ_PIN, pathname, 0)
431
432 static void
print_BPF_OBJ_PIN_first(const unsigned long addr)433 print_BPF_OBJ_PIN_first(const unsigned long addr)
434 {
435
436 printf("pathname=NULL, bpf_fd=0");
437 }
438
439 static unsigned int
init_BPF_OBJ_PIN_attr(const unsigned long eop)440 init_BPF_OBJ_PIN_attr(const unsigned long eop)
441 {
442 const union bpf_attr attr = {
443 .pathname = (uintptr_t) "/sys/fs/bpf/foo/bar",
444 .bpf_fd = -1
445 };
446 static const unsigned int offset =
447 offsetofend(union bpf_attr, bpf_fd);
448 const unsigned long addr = eop - offset;
449
450 memcpy((void *) addr, &attr, offset);
451 return offset;
452 }
453
454 static void
print_BPF_OBJ_PIN_attr(const unsigned long addr)455 print_BPF_OBJ_PIN_attr(const unsigned long addr)
456 {
457 printf("pathname=\"/sys/fs/bpf/foo/bar\", bpf_fd=-1");
458 }
459
460 # define init_BPF_OBJ_GET_first init_BPF_OBJ_PIN_first
461 # define print_BPF_OBJ_GET_first print_BPF_OBJ_PIN_first
462 # define init_BPF_OBJ_GET_attr init_BPF_OBJ_PIN_attr
463 # define print_BPF_OBJ_GET_attr print_BPF_OBJ_PIN_attr
464
465 # endif /* HAVE_UNION_BPF_ATTR_BPF_FD */
466
467 /* BPF_PROG_ATTACH and BPF_PROG_DETACH commands appear in kernel 4.10. */
468 # ifdef HAVE_UNION_BPF_ATTR_ATTACH_FLAGS
469
470 DEF_BPF_INIT_FIRST(BPF_PROG_ATTACH, target_fd, -1)
471
472 static void
print_BPF_PROG_ATTACH_first(const unsigned long addr)473 print_BPF_PROG_ATTACH_first(const unsigned long addr)
474 {
475 printf("target_fd=-1, attach_bpf_fd=0"
476 ", attach_type=BPF_CGROUP_INET_INGRESS, attach_flags=0");
477 }
478
479 static unsigned int
init_BPF_PROG_ATTACH_attr(const unsigned long eop)480 init_BPF_PROG_ATTACH_attr(const unsigned long eop)
481 {
482 static const union bpf_attr attr = {
483 .target_fd = -1,
484 .attach_bpf_fd = -2,
485 .attach_type = 2,
486 .attach_flags = 1
487 };
488 static const unsigned int offset =
489 offsetofend(union bpf_attr, attach_flags);
490 const unsigned long addr = eop - offset;
491
492 memcpy((void *) addr, &attr, offset);
493 return offset;
494 }
495
496 static void
print_BPF_PROG_ATTACH_attr(const unsigned long addr)497 print_BPF_PROG_ATTACH_attr(const unsigned long addr)
498 {
499 printf("target_fd=-1, attach_bpf_fd=-2"
500 ", attach_type=BPF_CGROUP_INET_SOCK_CREATE"
501 ", attach_flags=BPF_F_ALLOW_OVERRIDE");
502 }
503
504 # define init_BPF_PROG_DETACH_first init_BPF_PROG_ATTACH_first
505
506 static unsigned int
init_BPF_PROG_DETACH_attr(const unsigned long eop)507 init_BPF_PROG_DETACH_attr(const unsigned long eop)
508 {
509 static const union bpf_attr attr = {
510 .target_fd = -1,
511 .attach_type = 2
512 };
513 static const unsigned int offset =
514 offsetofend(union bpf_attr, attach_type);
515 const unsigned long addr = eop - offset;
516
517 memcpy((void *) addr, &attr, offset);
518 return offset;
519 }
520
521
522 static void
print_BPF_PROG_DETACH_first(const unsigned long addr)523 print_BPF_PROG_DETACH_first(const unsigned long addr)
524 {
525 printf("target_fd=-1, attach_type=BPF_CGROUP_INET_INGRESS");
526 }
527
528 static void
print_BPF_PROG_DETACH_attr(const unsigned long addr)529 print_BPF_PROG_DETACH_attr(const unsigned long addr)
530 {
531 printf("target_fd=-1, attach_type=BPF_CGROUP_INET_SOCK_CREATE");
532 }
533
534 # endif /* HAVE_UNION_BPF_ATTR_ATTACH_FLAGS */
535
536 /* BPF_PROG_TEST_RUN command appears in kernel 4.12. */
537 # ifdef HAVE_UNION_BPF_ATTR_TEST_DURATION
538
539 DEF_BPF_INIT_FIRST(BPF_PROG_TEST_RUN, test.prog_fd, -1)
540
541 static void
print_BPF_PROG_TEST_RUN_first(const unsigned long addr)542 print_BPF_PROG_TEST_RUN_first(const unsigned long addr)
543 {
544 printf("test={prog_fd=-1, retval=0, data_size_in=0, data_size_out=0"
545 ", data_in=0, data_out=0, repeat=0, duration=0}");
546 }
547
548 static const union bpf_attr sample_BPF_PROG_TEST_RUN_attr = {
549 .test = {
550 .prog_fd = -1,
551 .retval = 0xfac1fed2,
552 .data_size_in = 0xfac3fed4,
553 .data_size_out = 0xfac5fed6,
554 .data_in = (uint64_t) 0xfacef11dbadc2ded,
555 .data_out = (uint64_t) 0xfacef33dbadc4ded,
556 .repeat = 0xfac7fed8,
557 .duration = 0xfac9feda
558 }
559 };
560 static unsigned int
init_BPF_PROG_TEST_RUN_attr(const unsigned long eop)561 init_BPF_PROG_TEST_RUN_attr(const unsigned long eop)
562 {
563 static const unsigned int offset =
564 offsetofend(union bpf_attr, test);
565 const unsigned long addr = eop - offset;
566
567 memcpy((void *) addr, &sample_BPF_PROG_TEST_RUN_attr, offset);
568 return offset;
569 }
570
571 static void
print_BPF_PROG_TEST_RUN_attr(const unsigned long addr)572 print_BPF_PROG_TEST_RUN_attr(const unsigned long addr)
573 {
574 PRINT_FIELD_D("test={", sample_BPF_PROG_TEST_RUN_attr.test, prog_fd);
575 PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, retval);
576 PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_size_in);
577 PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_size_out);
578 PRINT_FIELD_X(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_in);
579 PRINT_FIELD_X(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_out);
580 PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, repeat);
581 PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, duration);
582 printf("}");
583 }
584
585 # endif /* HAVE_UNION_BPF_ATTR_TEST_DURATION */
586
587 # ifdef HAVE_UNION_BPF_ATTR_NEXT_ID
588
589 DEF_BPF_INIT_FIRST(BPF_PROG_GET_NEXT_ID, start_id, 0xdeadbeef)
590
591 static void
print_BPF_PROG_GET_NEXT_ID_first(const unsigned long addr)592 print_BPF_PROG_GET_NEXT_ID_first(const unsigned long addr)
593 {
594 printf("start_id=%u, next_id=0", 0xdeadbeef);
595 }
596
597 static unsigned int
init_BPF_PROG_GET_NEXT_ID_attr(const unsigned long eop)598 init_BPF_PROG_GET_NEXT_ID_attr(const unsigned long eop)
599 {
600 static const union bpf_attr attr = {
601 .start_id = 0xbadc0ded,
602 .next_id = 0xcafef00d
603 };
604 static const unsigned int offset =
605 offsetofend(union bpf_attr, next_id);
606 const unsigned long addr = eop - offset;
607
608 memcpy((void *) addr, &attr, offset);
609 return offset;
610 }
611
612 static void
print_BPF_PROG_GET_NEXT_ID_attr(const unsigned long addr)613 print_BPF_PROG_GET_NEXT_ID_attr(const unsigned long addr)
614 {
615 printf("start_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d);
616 }
617
618 # define init_BPF_MAP_GET_NEXT_ID_first init_BPF_PROG_GET_NEXT_ID_first
619 # define print_BPF_MAP_GET_NEXT_ID_first print_BPF_PROG_GET_NEXT_ID_first
620 # define init_BPF_MAP_GET_NEXT_ID_attr init_BPF_PROG_GET_NEXT_ID_attr
621 # define print_BPF_MAP_GET_NEXT_ID_attr print_BPF_PROG_GET_NEXT_ID_attr
622
623 # define init_BPF_PROG_GET_FD_BY_ID_first init_BPF_PROG_GET_NEXT_ID_first
624 # define init_BPF_PROG_GET_FD_BY_ID_attr init_BPF_PROG_GET_NEXT_ID_attr
625
626 static void
print_BPF_PROG_GET_FD_BY_ID_first(const unsigned long addr)627 print_BPF_PROG_GET_FD_BY_ID_first(const unsigned long addr)
628 {
629 printf("prog_id=%u, next_id=0", 0xdeadbeef);
630 }
631
632 static void
print_BPF_PROG_GET_FD_BY_ID_attr(const unsigned long addr)633 print_BPF_PROG_GET_FD_BY_ID_attr(const unsigned long addr)
634 {
635 printf("prog_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d);
636 }
637
638 # define init_BPF_MAP_GET_FD_BY_ID_first init_BPF_PROG_GET_NEXT_ID_first
639 # define init_BPF_MAP_GET_FD_BY_ID_attr init_BPF_PROG_GET_NEXT_ID_attr
640
641 static void
print_BPF_MAP_GET_FD_BY_ID_first(const unsigned long addr)642 print_BPF_MAP_GET_FD_BY_ID_first(const unsigned long addr)
643 {
644 printf("map_id=%u, next_id=0", 0xdeadbeef);
645 }
646
647 static void
print_BPF_MAP_GET_FD_BY_ID_attr(const unsigned long addr)648 print_BPF_MAP_GET_FD_BY_ID_attr(const unsigned long addr)
649 {
650 printf("map_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d);
651 }
652
653 # endif /* HAVE_UNION_BPF_ATTR_NEXT_ID */
654
655 # ifdef HAVE_UNION_BPF_ATTR_INFO_INFO
656
657 DEF_BPF_INIT_FIRST(BPF_OBJ_GET_INFO_BY_FD, info.bpf_fd, -1)
658
659 static void
print_BPF_OBJ_GET_INFO_BY_FD_first(const unsigned long addr)660 print_BPF_OBJ_GET_INFO_BY_FD_first(const unsigned long addr)
661 {
662 printf("info={bpf_fd=-1, info_len=0, info=0}");
663 }
664
665 static const union bpf_attr sample_BPF_OBJ_GET_INFO_BY_FD_attr = {
666 .info = {
667 .bpf_fd = -1,
668 .info_len = 0xdeadbeef,
669 .info = (uint64_t) 0xfacefeedbadc0ded
670 }
671 };
672 static unsigned int
init_BPF_OBJ_GET_INFO_BY_FD_attr(const unsigned long eop)673 init_BPF_OBJ_GET_INFO_BY_FD_attr(const unsigned long eop)
674 {
675 static const unsigned int offset =
676 offsetofend(union bpf_attr, info);
677 const unsigned long addr = eop - offset;
678
679 memcpy((void *) addr, &sample_BPF_OBJ_GET_INFO_BY_FD_attr, offset);
680 return offset;
681 }
682
683 static void
print_BPF_OBJ_GET_INFO_BY_FD_attr(const unsigned long addr)684 print_BPF_OBJ_GET_INFO_BY_FD_attr(const unsigned long addr)
685 {
686 PRINT_FIELD_D("info={", sample_BPF_OBJ_GET_INFO_BY_FD_attr.info, bpf_fd);
687 PRINT_FIELD_U(", ", sample_BPF_OBJ_GET_INFO_BY_FD_attr.info, info_len);
688 PRINT_FIELD_X(", ", sample_BPF_OBJ_GET_INFO_BY_FD_attr.info, info);
689 printf("}");
690 }
691
692 # endif /* HAVE_UNION_BPF_ATTR_INFO_INFO */
693
694 int
main(void)695 main(void)
696 {
697 page_size = get_page_size();
698 end_of_page = (unsigned long) tail_alloc(1) + 1;
699
700 # ifdef HAVE_UNION_BPF_ATTR_NUMA_NODE
701 TEST_BPF(BPF_MAP_CREATE);
702 # endif
703
704 # ifdef HAVE_UNION_BPF_ATTR_FLAGS
705 TEST_BPF(BPF_MAP_LOOKUP_ELEM);
706 TEST_BPF(BPF_MAP_UPDATE_ELEM);
707 TEST_BPF(BPF_MAP_DELETE_ELEM);
708 TEST_BPF(BPF_MAP_GET_NEXT_KEY);
709 # endif
710
711 # ifdef HAVE_UNION_BPF_ATTR_PROG_FLAGS
712 TEST_BPF(BPF_PROG_LOAD);
713 # endif
714
715 # ifdef HAVE_UNION_BPF_ATTR_BPF_FD
716 TEST_BPF(BPF_OBJ_PIN);
717 TEST_BPF(BPF_OBJ_GET);
718 # endif
719
720 # ifdef HAVE_UNION_BPF_ATTR_ATTACH_FLAGS
721 TEST_BPF(BPF_PROG_ATTACH);
722 TEST_BPF(BPF_PROG_DETACH);
723 # endif
724
725 # ifdef HAVE_UNION_BPF_ATTR_TEST_DURATION
726 TEST_BPF(BPF_PROG_TEST_RUN);
727 # endif
728
729 # ifdef HAVE_UNION_BPF_ATTR_NEXT_ID
730 TEST_BPF(BPF_PROG_GET_NEXT_ID);
731 TEST_BPF(BPF_MAP_GET_NEXT_ID);
732 TEST_BPF(BPF_PROG_GET_FD_BY_ID);
733 TEST_BPF(BPF_MAP_GET_FD_BY_ID);
734 # endif
735
736 # ifdef HAVE_UNION_BPF_ATTR_INFO_INFO
737 TEST_BPF(BPF_OBJ_GET_INFO_BY_FD);
738 # endif
739
740 sys_bpf(0xfacefeed, end_of_page, 40);
741 printf("bpf(0xfacefeed /* BPF_??? */, %#lx, 40) = %s\n",
742 end_of_page, errstr);
743
744 puts("+++ exited with 0 +++");
745 return 0;
746 }
747
748 #else
749
750 SKIP_MAIN_UNDEFINED("__NR_bpf && HAVE_UNION_BPF_ATTR_*")
751
752 #endif
753