• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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