]> granicus.if.org Git - strace/blob - tests/bpf.c
Implement decoding of BPF_OBJ_GET_INFO_BY_FD command of bpf syscall
[strace] / tests / bpf.c
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
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 # ifdef HAVE_UNION_BPF_ATTR_NUMA_NODE
191
192 static unsigned int
193 init_BPF_MAP_CREATE_first(const unsigned long eop)
194 {
195         static const union bpf_attr attr = { .map_type = 2 };
196         static const unsigned int offset = sizeof(attr.map_type);
197         const unsigned long addr = eop - offset;
198
199         memcpy((void *) addr, &attr.map_type, offset);
200         return offset;
201 }
202
203 static void
204 print_BPF_MAP_CREATE_first(const unsigned long addr)
205 {
206         printf("map_type=BPF_MAP_TYPE_ARRAY, key_size=0, value_size=0"
207                ", max_entries=0, map_flags=0, inner_map_fd=0");
208 }
209
210 static unsigned int
211 init_BPF_MAP_CREATE_attr(const unsigned long eop)
212 {
213         static const union bpf_attr attr = {
214                 .map_type = 1,
215                 .key_size = 4,
216                 .value_size = 8,
217                 .max_entries = 256,
218                 .map_flags = 7,
219                 .inner_map_fd = -1,
220                 .numa_node = 42
221         };
222         static const unsigned int offset =
223                 offsetofend(union bpf_attr, numa_node);
224         const unsigned long addr = eop - offset;
225
226         memcpy((void *) addr, &attr, offset);
227         return offset;
228 }
229
230 static void
231 print_BPF_MAP_CREATE_attr(const unsigned long addr)
232 {
233         printf("map_type=BPF_MAP_TYPE_HASH, key_size=4"
234                ", value_size=8, max_entries=256"
235                ", map_flags=BPF_F_NO_PREALLOC|BPF_F_NO_COMMON_LRU"
236                "|BPF_F_NUMA_NODE, inner_map_fd=-1, numa_node=42");
237 }
238
239 # endif /* HAVE_UNION_BPF_ATTR_NUMA_NODE */
240
241 # ifdef HAVE_UNION_BPF_ATTR_FLAGS
242
243 static unsigned int
244 init_BPF_MAP_LOOKUP_ELEM_first(const unsigned long eop)
245 {
246         static const union bpf_attr attr = { .map_fd = -1 };
247         static const unsigned int offset = sizeof(attr.map_fd);
248         const unsigned long addr = eop - offset;
249
250         memcpy((void *) addr, &attr.map_fd, offset);
251         return offset;
252 }
253
254 static void
255 print_BPF_MAP_LOOKUP_ELEM_first(const unsigned long addr)
256 {
257         printf("map_fd=-1, key=0, value=0");
258 }
259
260 static unsigned int
261 init_BPF_MAP_LOOKUP_ELEM_attr(const unsigned long eop)
262 {
263         static const union bpf_attr attr = {
264                 .map_fd = -1,
265                 .key = 0xdeadbeef,
266                 .value = 0xbadc0ded
267         };
268         static const unsigned int offset =
269                 offsetofend(union bpf_attr, value);
270         const unsigned long addr = eop - offset;
271
272         memcpy((void *) addr, &attr, offset);
273         return offset;
274 }
275
276 static void
277 print_BPF_MAP_LOOKUP_ELEM_attr(const unsigned long addr)
278 {
279         printf("map_fd=-1, key=0xdeadbeef, value=0xbadc0ded");
280 }
281
282 #  define init_BPF_MAP_UPDATE_ELEM_first init_BPF_MAP_LOOKUP_ELEM_first
283
284 static void
285 print_BPF_MAP_UPDATE_ELEM_first(const unsigned long addr)
286 {
287         printf("map_fd=-1, key=0, value=0, flags=BPF_ANY");
288 }
289
290 static unsigned int
291 init_BPF_MAP_UPDATE_ELEM_attr(const unsigned long eop)
292 {
293         static const union bpf_attr attr = {
294                 .map_fd = -1,
295                 .key = 0xdeadbeef,
296                 .value = 0xbadc0ded,
297                 .flags = 2
298         };
299         static const unsigned int offset =
300                 offsetofend(union bpf_attr, flags);
301         const unsigned long addr = eop - offset;
302
303         memcpy((void *) addr, &attr, offset);
304         return offset;
305 }
306
307 static void
308 print_BPF_MAP_UPDATE_ELEM_attr(const unsigned long addr)
309 {
310         printf("map_fd=-1, key=0xdeadbeef, value=0xbadc0ded, flags=BPF_EXIST");
311 }
312
313 #  define init_BPF_MAP_DELETE_ELEM_first init_BPF_MAP_LOOKUP_ELEM_first
314
315 static void
316 print_BPF_MAP_DELETE_ELEM_first(const unsigned long addr)
317 {
318         printf("map_fd=-1, key=0");
319 }
320
321 static unsigned int
322 init_BPF_MAP_DELETE_ELEM_attr(const unsigned long eop)
323 {
324         static const union bpf_attr attr = {
325                 .map_fd = -1,
326                 .key = 0xdeadbeef
327         };
328         static const unsigned int offset =
329                 offsetofend(union bpf_attr, key);
330         const unsigned long addr = eop - offset;
331
332         memcpy((void *) addr, &attr, offset);
333         return offset;
334 }
335
336 static void
337 print_BPF_MAP_DELETE_ELEM_attr(const unsigned long addr)
338 {
339         printf("map_fd=-1, key=0xdeadbeef");
340 }
341
342 #  define init_BPF_MAP_GET_NEXT_KEY_first init_BPF_MAP_LOOKUP_ELEM_first
343
344 static void
345 print_BPF_MAP_GET_NEXT_KEY_first(const unsigned long addr)
346 {
347         printf("map_fd=-1, key=0, next_key=0");
348 }
349
350 static unsigned int
351 init_BPF_MAP_GET_NEXT_KEY_attr(const unsigned long eop)
352 {
353         static const union bpf_attr attr = {
354                 .map_fd = -1,
355                 .key = 0xdeadbeef,
356                 .next_key = 0xbadc0ded
357         };
358         static const unsigned int offset =
359                 offsetofend(union bpf_attr, next_key);
360         const unsigned long addr = eop - offset;
361
362         memcpy((void *) addr, &attr, offset);
363         return offset;
364 }
365
366 static void
367 print_BPF_MAP_GET_NEXT_KEY_attr(const unsigned long addr)
368 {
369         printf("map_fd=-1, key=0xdeadbeef, next_key=0xbadc0ded");
370 }
371
372 # endif /* HAVE_UNION_BPF_ATTR_FLAGS */
373
374 # ifdef HAVE_UNION_BPF_ATTR_PROG_FLAGS
375
376 static unsigned int
377 init_BPF_PROG_LOAD_first(const unsigned long eop)
378 {
379         static const union bpf_attr attr = { .prog_type = 1 };
380         static const unsigned int offset = sizeof(attr.prog_type);
381         const unsigned long addr = eop - offset;
382
383         memcpy((void *) addr, &attr.prog_type, offset);
384         return offset;
385 }
386
387 static void
388 print_BPF_PROG_LOAD_first(const unsigned long addr)
389 {
390
391         printf("prog_type=BPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=0, insns=0"
392                ", license=NULL, log_level=0, log_size=0, log_buf=0"
393                ", kern_version=0, prog_flags=0");
394 }
395
396 static const struct bpf_insn insns[] = {
397         { .code = BPF_JMP | BPF_EXIT }
398 };
399 static char log_buf[4096];
400
401 static unsigned int
402 init_BPF_PROG_LOAD_attr(const unsigned long eop)
403 {
404         const union bpf_attr attr = {
405                 .prog_type = 1,
406                 .insn_cnt = ARRAY_SIZE(insns),
407                 .insns = (uintptr_t) insns,
408                 .license = (uintptr_t) "GPL",
409                 .log_level = 42,
410                 .log_size = sizeof(log_buf),
411                 .log_buf = (uintptr_t) log_buf,
412                 .kern_version = 0xcafef00d,
413                 .prog_flags = 1
414         };
415         static const unsigned int offset =
416                 offsetofend(union bpf_attr, prog_flags);
417         const unsigned long addr = eop - offset;
418
419         memcpy((void *) addr, &attr, offset);
420         return offset;
421 }
422
423 static void
424 print_BPF_PROG_LOAD_attr(const unsigned long addr)
425 {
426         printf("prog_type=BPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=%u, insns=%p"
427                ", license=\"GPL\", log_level=42, log_size=4096, log_buf=%p"
428                ", kern_version=%u, prog_flags=BPF_F_STRICT_ALIGNMENT",
429                (unsigned int) ARRAY_SIZE(insns), insns,
430                log_buf, 0xcafef00d);
431 }
432
433 # endif /* HAVE_UNION_BPF_ATTR_PROG_FLAGS */
434
435 /*
436  * bpf() syscall and its first six commands were introduced in Linux kernel
437  * 3.18. Some additional commands were added afterwards, so we need to take
438  * precautions to make sure the tests compile.
439  *
440  * BPF_OBJ_PIN and BPF_OBJ_GET commands appear in kernel 4.4.
441  */
442 # ifdef HAVE_UNION_BPF_ATTR_BPF_FD
443
444 static unsigned int
445 init_BPF_OBJ_PIN_first(const unsigned long eop)
446 {
447         static const union bpf_attr attr = {};
448         static const unsigned int offset = sizeof(attr.pathname);
449         const unsigned long addr = eop - offset;
450
451         memcpy((void *) addr, &attr.pathname, offset);
452         return offset;
453 }
454
455 static void
456 print_BPF_OBJ_PIN_first(const unsigned long addr)
457 {
458
459         printf("pathname=NULL, bpf_fd=0");
460 }
461
462 static unsigned int
463 init_BPF_OBJ_PIN_attr(const unsigned long eop)
464 {
465         const union bpf_attr attr = {
466                 .pathname = (uintptr_t) "/sys/fs/bpf/foo/bar",
467                 .bpf_fd = -1
468         };
469         static const unsigned int offset =
470                 offsetofend(union bpf_attr, bpf_fd);
471         const unsigned long addr = eop - offset;
472
473         memcpy((void *) addr, &attr, offset);
474         return offset;
475 }
476
477 static void
478 print_BPF_OBJ_PIN_attr(const unsigned long addr)
479 {
480         printf("pathname=\"/sys/fs/bpf/foo/bar\", bpf_fd=-1");
481 }
482
483 #  define init_BPF_OBJ_GET_first init_BPF_OBJ_PIN_first
484 #  define print_BPF_OBJ_GET_first print_BPF_OBJ_PIN_first
485 #  define init_BPF_OBJ_GET_attr init_BPF_OBJ_PIN_attr
486 #  define print_BPF_OBJ_GET_attr print_BPF_OBJ_PIN_attr
487
488 # endif /* HAVE_UNION_BPF_ATTR_BPF_FD */
489
490 /* BPF_PROG_ATTACH and BPF_PROG_DETACH commands appear in kernel 4.10. */
491 # ifdef HAVE_UNION_BPF_ATTR_ATTACH_FLAGS
492
493 static unsigned int
494 init_BPF_PROG_ATTACH_first(const unsigned long eop)
495 {
496         static const union bpf_attr attr = { .target_fd = -1 };
497         static const unsigned int offset = sizeof(attr.target_fd);
498         const unsigned long addr = eop - offset;
499
500         memcpy((void *) addr, &attr.target_fd, offset);
501         return offset;
502 }
503
504 static void
505 print_BPF_PROG_ATTACH_first(const unsigned long addr)
506 {
507         printf("target_fd=-1, attach_bpf_fd=0"
508                ", attach_type=BPF_CGROUP_INET_INGRESS, attach_flags=0");
509 }
510
511 static unsigned int
512 init_BPF_PROG_ATTACH_attr(const unsigned long eop)
513 {
514         static const union bpf_attr attr = {
515                 .target_fd = -1,
516                 .attach_bpf_fd = -2,
517                 .attach_type = 2,
518                 .attach_flags = 1
519         };
520         static const unsigned int offset =
521                 offsetofend(union bpf_attr, attach_flags);
522         const unsigned long addr = eop - offset;
523
524         memcpy((void *) addr, &attr, offset);
525         return offset;
526 }
527
528 static void
529 print_BPF_PROG_ATTACH_attr(const unsigned long addr)
530 {
531         printf("target_fd=-1, attach_bpf_fd=-2"
532                ", attach_type=BPF_CGROUP_INET_SOCK_CREATE"
533                ", attach_flags=BPF_F_ALLOW_OVERRIDE");
534 }
535
536 #  define init_BPF_PROG_DETACH_first init_BPF_PROG_ATTACH_first
537
538 static unsigned int
539 init_BPF_PROG_DETACH_attr(const unsigned long eop)
540 {
541         static const union bpf_attr attr = {
542                 .target_fd = -1,
543                 .attach_type = 2
544         };
545         static const unsigned int offset =
546                 offsetofend(union bpf_attr, attach_type);
547         const unsigned long addr = eop - offset;
548
549         memcpy((void *) addr, &attr, offset);
550         return offset;
551 }
552
553
554 static void
555 print_BPF_PROG_DETACH_first(const unsigned long addr)
556 {
557         printf("target_fd=-1, attach_type=BPF_CGROUP_INET_INGRESS");
558 }
559
560 static void
561 print_BPF_PROG_DETACH_attr(const unsigned long addr)
562 {
563         printf("target_fd=-1, attach_type=BPF_CGROUP_INET_SOCK_CREATE");
564 }
565
566 # endif /* HAVE_UNION_BPF_ATTR_ATTACH_FLAGS */
567
568 /* BPF_PROG_TEST_RUN command appears in kernel 4.12. */
569 # ifdef HAVE_UNION_BPF_ATTR_TEST_DURATION
570
571 static unsigned int
572 init_BPF_PROG_TEST_RUN_first(const unsigned long eop)
573 {
574         static const union bpf_attr attr = { .test.prog_fd = -1 };
575         static const unsigned int offset = sizeof(attr.test.prog_fd);
576         const unsigned long addr = eop - offset;
577
578         memcpy((void *) addr, &attr.test.prog_fd, offset);
579         return offset;
580 }
581
582 static void
583 print_BPF_PROG_TEST_RUN_first(const unsigned long addr)
584 {
585         printf("test={prog_fd=-1, retval=0, data_size_in=0, data_size_out=0"
586                ", data_in=0, data_out=0, repeat=0, duration=0}");
587 }
588
589 static const union bpf_attr sample_BPF_PROG_TEST_RUN_attr = {
590         .test = {
591                 .prog_fd = -1,
592                 .retval = 0xfac1fed2,
593                 .data_size_in = 0xfac3fed4,
594                 .data_size_out = 0xfac5fed6,
595                 .data_in = (uint64_t) 0xfacef11dbadc2ded,
596                 .data_out = (uint64_t) 0xfacef33dbadc4ded,
597                 .repeat = 0xfac7fed8,
598                 .duration = 0xfac9feda
599         }
600 };
601 static unsigned int
602 init_BPF_PROG_TEST_RUN_attr(const unsigned long eop)
603 {
604         static const unsigned int offset =
605                 offsetofend(union bpf_attr, test);
606         const unsigned long addr = eop - offset;
607
608         memcpy((void *) addr, &sample_BPF_PROG_TEST_RUN_attr, offset);
609         return offset;
610 }
611
612 static void
613 print_BPF_PROG_TEST_RUN_attr(const unsigned long addr)
614 {
615         PRINT_FIELD_D("test={", sample_BPF_PROG_TEST_RUN_attr.test, prog_fd);
616         PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, retval);
617         PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_size_in);
618         PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_size_out);
619         PRINT_FIELD_X(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_in);
620         PRINT_FIELD_X(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_out);
621         PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, repeat);
622         PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, duration);
623         printf("}");
624 }
625
626 # endif /* HAVE_UNION_BPF_ATTR_TEST_DURATION */
627
628 # ifdef HAVE_UNION_BPF_ATTR_NEXT_ID
629
630 static unsigned int
631 init_BPF_PROG_GET_NEXT_ID_first(const unsigned long eop)
632 {
633         static const union bpf_attr attr = { .start_id = 0xdeadbeef };
634         static const unsigned int offset = sizeof(attr.start_id);
635         const unsigned long addr = eop - offset;
636
637         memcpy((void *) addr, &attr.start_id, offset);
638         return offset;
639 }
640
641 static void
642 print_BPF_PROG_GET_NEXT_ID_first(const unsigned long addr)
643 {
644         printf("start_id=%u, next_id=0", 0xdeadbeef);
645 }
646
647 static unsigned int
648 init_BPF_PROG_GET_NEXT_ID_attr(const unsigned long eop)
649 {
650         static const union bpf_attr attr = {
651                 .start_id = 0xbadc0ded,
652                 .next_id = 0xcafef00d
653         };
654         static const unsigned int offset =
655                 offsetofend(union bpf_attr, next_id);
656         const unsigned long addr = eop - offset;
657
658         memcpy((void *) addr, &attr, offset);
659         return offset;
660 }
661
662 static void
663 print_BPF_PROG_GET_NEXT_ID_attr(const unsigned long addr)
664 {
665         printf("start_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d);
666 }
667
668 #  define init_BPF_MAP_GET_NEXT_ID_first init_BPF_PROG_GET_NEXT_ID_first
669 #  define print_BPF_MAP_GET_NEXT_ID_first print_BPF_PROG_GET_NEXT_ID_first
670 #  define init_BPF_MAP_GET_NEXT_ID_attr init_BPF_PROG_GET_NEXT_ID_attr
671 #  define print_BPF_MAP_GET_NEXT_ID_attr print_BPF_PROG_GET_NEXT_ID_attr
672
673 #  define init_BPF_PROG_GET_FD_BY_ID_first init_BPF_PROG_GET_NEXT_ID_first
674 #  define init_BPF_PROG_GET_FD_BY_ID_attr init_BPF_PROG_GET_NEXT_ID_attr
675
676 static void
677 print_BPF_PROG_GET_FD_BY_ID_first(const unsigned long addr)
678 {
679         printf("prog_id=%u, next_id=0", 0xdeadbeef);
680 }
681
682 static void
683 print_BPF_PROG_GET_FD_BY_ID_attr(const unsigned long addr)
684 {
685         printf("prog_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d);
686 }
687
688 #  define init_BPF_MAP_GET_FD_BY_ID_first init_BPF_PROG_GET_NEXT_ID_first
689 #  define init_BPF_MAP_GET_FD_BY_ID_attr init_BPF_PROG_GET_NEXT_ID_attr
690
691 static void
692 print_BPF_MAP_GET_FD_BY_ID_first(const unsigned long addr)
693 {
694         printf("map_id=%u, next_id=0", 0xdeadbeef);
695 }
696
697 static void
698 print_BPF_MAP_GET_FD_BY_ID_attr(const unsigned long addr)
699 {
700         printf("map_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d);
701 }
702
703 # endif /* HAVE_UNION_BPF_ATTR_NEXT_ID */
704
705 # ifdef HAVE_UNION_BPF_ATTR_INFO_INFO
706
707 static unsigned int
708 init_BPF_OBJ_GET_INFO_BY_FD_first(const unsigned long eop)
709 {
710         static const union bpf_attr attr = { .info.bpf_fd = -1 };
711         static const unsigned int offset = sizeof(attr.info.bpf_fd);
712         const unsigned long addr = eop - offset;
713
714         memcpy((void *) addr, &attr.info.bpf_fd, offset);
715         return offset;
716 }
717
718 static void
719 print_BPF_OBJ_GET_INFO_BY_FD_first(const unsigned long addr)
720 {
721         printf("info={bpf_fd=-1, info_len=0, info=0}");
722 }
723
724 static const union bpf_attr sample_BPF_OBJ_GET_INFO_BY_FD_attr = {
725         .info = {
726                 .bpf_fd = -1,
727                 .info_len = 0xdeadbeef,
728                 .info = (uint64_t) 0xfacefeedbadc0ded
729         }
730 };
731 static unsigned int
732 init_BPF_OBJ_GET_INFO_BY_FD_attr(const unsigned long eop)
733 {
734         static const unsigned int offset =
735                 offsetofend(union bpf_attr, info);
736         const unsigned long addr = eop - offset;
737
738         memcpy((void *) addr, &sample_BPF_OBJ_GET_INFO_BY_FD_attr, offset);
739         return offset;
740 }
741
742 static void
743 print_BPF_OBJ_GET_INFO_BY_FD_attr(const unsigned long addr)
744 {
745         PRINT_FIELD_D("info={", sample_BPF_OBJ_GET_INFO_BY_FD_attr.info, bpf_fd);
746         PRINT_FIELD_U(", ", sample_BPF_OBJ_GET_INFO_BY_FD_attr.info, info_len);
747         PRINT_FIELD_X(", ", sample_BPF_OBJ_GET_INFO_BY_FD_attr.info, info);
748         printf("}");
749 }
750
751 # endif /* HAVE_UNION_BPF_ATTR_INFO_INFO */
752
753 int
754 main(void)
755 {
756         page_size = get_page_size();
757         end_of_page = (unsigned long) tail_alloc(1) + 1;
758
759 # ifdef HAVE_UNION_BPF_ATTR_NUMA_NODE
760         TEST_BPF(BPF_MAP_CREATE);
761 # endif
762
763 # ifdef HAVE_UNION_BPF_ATTR_FLAGS
764         TEST_BPF(BPF_MAP_LOOKUP_ELEM);
765         TEST_BPF(BPF_MAP_UPDATE_ELEM);
766         TEST_BPF(BPF_MAP_DELETE_ELEM);
767         TEST_BPF(BPF_MAP_GET_NEXT_KEY);
768 # endif
769
770 # ifdef HAVE_UNION_BPF_ATTR_PROG_FLAGS
771         TEST_BPF(BPF_PROG_LOAD);
772 # endif
773
774 # ifdef HAVE_UNION_BPF_ATTR_BPF_FD
775         TEST_BPF(BPF_OBJ_PIN);
776         TEST_BPF(BPF_OBJ_GET);
777 # endif
778
779 # ifdef HAVE_UNION_BPF_ATTR_ATTACH_FLAGS
780         TEST_BPF(BPF_PROG_ATTACH);
781         TEST_BPF(BPF_PROG_DETACH);
782 # endif
783
784 # ifdef HAVE_UNION_BPF_ATTR_TEST_DURATION
785         TEST_BPF(BPF_PROG_TEST_RUN);
786 # endif
787
788 # ifdef HAVE_UNION_BPF_ATTR_NEXT_ID
789         TEST_BPF(BPF_PROG_GET_NEXT_ID);
790         TEST_BPF(BPF_MAP_GET_NEXT_ID);
791         TEST_BPF(BPF_PROG_GET_FD_BY_ID);
792         TEST_BPF(BPF_MAP_GET_FD_BY_ID);
793 # endif
794
795 # ifdef HAVE_UNION_BPF_ATTR_INFO_INFO
796         TEST_BPF(BPF_OBJ_GET_INFO_BY_FD);
797 # endif
798
799         sys_bpf(0xfacefeed, end_of_page, 40);
800         printf("bpf(0xfacefeed /* BPF_??? */, %#lx, 40) = %s\n",
801                end_of_page, errstr);
802
803         puts("+++ exited with 0 +++");
804         return 0;
805 }
806
807 #else
808
809 SKIP_MAIN_UNDEFINED("__NR_bpf && HAVE_UNION_BPF_ATTR_*")
810
811 #endif