Home | History | Annotate | Download | only in tests
      1 /*
      2  * Check bpf syscall decoding.
      3  *
      4  * Copyright (c) 2015-2017 Dmitry V. Levin <ldv (at) 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 #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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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