2 * Check bpf syscall decoding.
4 * Copyright (c) 2015-2017 Dmitry V. Levin <ldv@altlinux.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
31 #include <asm/unistd.h>
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_NUMA_NODE \
38 || defined HAVE_UNION_BPF_ATTR_PROG_FLAGS)
45 # include <linux/bpf.h>
47 static const kernel_ulong_t long_bits = (kernel_ulong_t) 0xfacefeed00000000ULL;
48 static const char *errstr;
49 static unsigned int sizeof_attr = sizeof(union bpf_attr);
50 static unsigned int page_size;
51 static unsigned long end_of_page;
54 sys_bpf(kernel_ulong_t cmd, kernel_ulong_t attr, kernel_ulong_t size)
56 long rc = syscall(__NR_bpf, cmd, attr, size);
57 errstr = sprintrc(rc);
62 # define print_extra_data(addr_, size_) print_quoted_hex((addr_), (size_))
64 # define print_extra_data(addr_, size_) printf("...")
67 # define TEST_BPF_(cmd_, cmd_str_, \
68 init_first_, print_first_, \
69 init_attr_, print_attr_) \
72 sys_bpf(cmd_, 0, long_bits | sizeof(union bpf_attr)); \
73 printf("bpf(%s, NULL, %u) = %s\n", \
74 cmd_str_, sizeof_attr, errstr); \
77 unsigned long addr = end_of_page - sizeof_attr; \
78 sys_bpf(cmd_, addr, long_bits); \
79 printf("bpf(%s, %#lx, 0) = %s\n", \
80 cmd_str_, addr, errstr); \
82 /* the first field only */ \
83 unsigned int offset = init_first_(end_of_page); \
84 addr = end_of_page - offset; \
85 sys_bpf(cmd_, addr, offset); \
86 printf("bpf(%s, {", cmd_str_); \
88 printf("}, %u) = %s\n", offset, errstr); \
90 /* efault after the first field */ \
91 sys_bpf(cmd_, addr, offset + 1); \
92 printf("bpf(%s, %#lx, %u) = %s\n", \
93 cmd_str_, addr, offset + 1, errstr); \
95 /* the relevant part of union bpf_attr */ \
96 offset = init_attr_(end_of_page); \
97 addr = end_of_page - offset; \
98 sys_bpf(cmd_, addr, offset); \
99 printf("bpf(%s, {", cmd_str_); \
101 printf("}, %u) = %s\n", offset, errstr); \
103 /* short read of the relevant part of union bpf_attr */ \
104 sys_bpf(cmd_, addr + 1, offset); \
105 printf("bpf(%s, %#lx, %u) = %s\n", \
106 cmd_str_, addr + 1, offset, errstr); \
108 if (offset < sizeof_attr) { \
109 /* short read of the whole union bpf_attr */ \
110 memmove((void *) end_of_page - sizeof_attr + 1, \
111 (void *) addr, offset); \
112 addr = end_of_page - sizeof_attr + 1; \
113 memset((void *) addr + offset, 0, \
114 sizeof_attr - offset - 1); \
115 sys_bpf(cmd_, addr, sizeof_attr); \
116 printf("bpf(%s, %#lx, %u) = %s\n", \
117 cmd_str_, addr, sizeof_attr, errstr); \
119 /* the whole union bpf_attr */ \
120 memmove((void *) end_of_page - sizeof_attr, \
121 (void *) addr, offset); \
122 addr = end_of_page - sizeof_attr; \
123 memset((void *) addr + offset, 0, \
124 sizeof_attr - offset); \
125 sys_bpf(cmd_, addr, sizeof_attr); \
126 printf("bpf(%s, {", cmd_str_); \
128 printf("}, %u) = %s\n", sizeof_attr, errstr); \
130 /* non-zero bytes after the relevant part */ \
131 fill_memory_ex((void *) addr + offset, \
132 sizeof_attr - offset, '0', 10); \
133 sys_bpf(cmd_, addr, sizeof_attr); \
134 printf("bpf(%s, {", cmd_str_); \
137 print_extra_data((void *) addr + offset, \
138 sizeof_attr - offset); \
139 printf("}, %u) = %s\n", sizeof_attr, errstr); \
142 /* short read of the whole page */ \
143 memmove((void *) end_of_page - page_size + 1, \
144 (void *) addr, offset); \
145 addr = end_of_page - page_size + 1; \
146 memset((void *) addr + offset, 0, \
147 page_size - offset - 1); \
148 sys_bpf(cmd_, addr, page_size); \
149 printf("bpf(%s, %#lx, %u) = %s\n", \
150 cmd_str_, addr, page_size, errstr); \
152 /* the whole page */ \
153 memmove((void *) end_of_page - page_size, \
154 (void *) addr, offset); \
155 addr = end_of_page - page_size; \
156 memset((void *) addr + offset, 0, page_size - offset); \
157 sys_bpf(cmd_, addr, page_size); \
158 printf("bpf(%s, {", cmd_str_); \
160 printf("}, %u) = %s\n", page_size, errstr); \
162 /* non-zero bytes after the whole union bpf_attr */ \
163 fill_memory_ex((void *) addr + offset, \
164 page_size - offset, '0', 10); \
165 sys_bpf(cmd_, addr, page_size); \
166 printf("bpf(%s, {", cmd_str_); \
169 print_extra_data((void *) addr + offset, \
170 page_size - offset); \
171 printf("}, %u) = %s\n", page_size, errstr); \
173 /* more than a page */ \
174 sys_bpf(cmd_, addr, page_size + 1); \
175 printf("bpf(%s, %#lx, %u) = %s\n", \
176 cmd_str_, addr, page_size + 1, errstr); \
178 /* End of TEST_BPF_ definition. */
180 # define TEST_BPF(cmd_) \
181 TEST_BPF_((cmd_), #cmd_, \
182 init_ ## cmd_ ## _first, print_ ## cmd_ ## _first, \
183 init_ ## cmd_ ## _attr, print_ ## cmd_ ## _attr) \
184 /* End of TEST_BPF definition. */
186 # ifdef HAVE_UNION_BPF_ATTR_NUMA_NODE
189 init_BPF_MAP_CREATE_first(const unsigned long eop)
191 static const union bpf_attr attr = { .map_type = 2 };
192 static const unsigned int offset = sizeof(attr.map_type);
193 const unsigned long addr = eop - offset;
195 memcpy((void *) addr, &attr.map_type, offset);
200 print_BPF_MAP_CREATE_first(const unsigned long addr)
202 printf("map_type=BPF_MAP_TYPE_ARRAY, key_size=0, value_size=0"
203 ", max_entries=0, map_flags=0, inner_map_fd=0");
207 init_BPF_MAP_CREATE_attr(const unsigned long eop)
209 static const union bpf_attr attr = {
218 static const unsigned int offset =
219 offsetofend(union bpf_attr, numa_node);
220 const unsigned long addr = eop - offset;
222 memcpy((void *) addr, &attr, offset);
227 print_BPF_MAP_CREATE_attr(const unsigned long addr)
229 printf("map_type=BPF_MAP_TYPE_HASH, key_size=4"
230 ", value_size=8, max_entries=256"
231 ", map_flags=BPF_F_NO_PREALLOC|BPF_F_NO_COMMON_LRU"
232 "|BPF_F_NUMA_NODE, inner_map_fd=-1, numa_node=42");
235 # endif /* HAVE_UNION_BPF_ATTR_NUMA_NODE */
237 # ifdef HAVE_UNION_BPF_ATTR_FLAGS
240 init_BPF_MAP_LOOKUP_ELEM_first(const unsigned long eop)
242 static const union bpf_attr attr = { .map_fd = -1 };
243 static const unsigned int offset = sizeof(attr.map_fd);
244 const unsigned long addr = eop - offset;
246 memcpy((void *) addr, &attr.map_fd, offset);
251 print_BPF_MAP_LOOKUP_ELEM_first(const unsigned long addr)
253 printf("map_fd=-1, key=0, value=0");
257 init_BPF_MAP_LOOKUP_ELEM_attr(const unsigned long eop)
259 static const union bpf_attr attr = {
264 static const unsigned int offset =
265 offsetofend(union bpf_attr, value);
266 const unsigned long addr = eop - offset;
268 memcpy((void *) addr, &attr, offset);
273 print_BPF_MAP_LOOKUP_ELEM_attr(const unsigned long addr)
275 printf("map_fd=-1, key=0xdeadbeef, value=0xbadc0ded");
278 # define init_BPF_MAP_UPDATE_ELEM_first init_BPF_MAP_LOOKUP_ELEM_first
281 print_BPF_MAP_UPDATE_ELEM_first(const unsigned long addr)
283 printf("map_fd=-1, key=0, value=0, flags=BPF_ANY");
287 init_BPF_MAP_UPDATE_ELEM_attr(const unsigned long eop)
289 static const union bpf_attr attr = {
295 static const unsigned int offset =
296 offsetofend(union bpf_attr, flags);
297 const unsigned long addr = eop - offset;
299 memcpy((void *) addr, &attr, offset);
304 print_BPF_MAP_UPDATE_ELEM_attr(const unsigned long addr)
306 printf("map_fd=-1, key=0xdeadbeef, value=0xbadc0ded, flags=BPF_EXIST");
309 # define init_BPF_MAP_DELETE_ELEM_first init_BPF_MAP_LOOKUP_ELEM_first
312 print_BPF_MAP_DELETE_ELEM_first(const unsigned long addr)
314 printf("map_fd=-1, key=0");
318 init_BPF_MAP_DELETE_ELEM_attr(const unsigned long eop)
320 static const union bpf_attr attr = {
324 static const unsigned int offset =
325 offsetofend(union bpf_attr, key);
326 const unsigned long addr = eop - offset;
328 memcpy((void *) addr, &attr, offset);
333 print_BPF_MAP_DELETE_ELEM_attr(const unsigned long addr)
335 printf("map_fd=-1, key=0xdeadbeef");
338 # define init_BPF_MAP_GET_NEXT_KEY_first init_BPF_MAP_LOOKUP_ELEM_first
341 print_BPF_MAP_GET_NEXT_KEY_first(const unsigned long addr)
343 printf("map_fd=-1, key=0, next_key=0");
347 init_BPF_MAP_GET_NEXT_KEY_attr(const unsigned long eop)
349 static const union bpf_attr attr = {
352 .next_key = 0xbadc0ded
354 static const unsigned int offset =
355 offsetofend(union bpf_attr, next_key);
356 const unsigned long addr = eop - offset;
358 memcpy((void *) addr, &attr, offset);
363 print_BPF_MAP_GET_NEXT_KEY_attr(const unsigned long addr)
365 printf("map_fd=-1, key=0xdeadbeef, next_key=0xbadc0ded");
368 # endif /* HAVE_UNION_BPF_ATTR_FLAGS */
370 # ifdef HAVE_UNION_BPF_ATTR_PROG_FLAGS
373 init_BPF_PROG_LOAD_first(const unsigned long eop)
375 static const union bpf_attr attr = { .prog_type = 1 };
376 static const unsigned int offset = sizeof(attr.prog_type);
377 const unsigned long addr = eop - offset;
379 memcpy((void *) addr, &attr.prog_type, offset);
384 print_BPF_PROG_LOAD_first(const unsigned long addr)
387 printf("prog_type=BPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=0, insns=0"
388 ", license=NULL, log_level=0, log_size=0, log_buf=0"
389 ", kern_version=0, prog_flags=0");
392 static const struct bpf_insn insns[] = {
393 { .code = BPF_JMP | BPF_EXIT }
395 static char log_buf[4096];
398 init_BPF_PROG_LOAD_attr(const unsigned long eop)
400 const union bpf_attr attr = {
402 .insn_cnt = ARRAY_SIZE(insns),
403 .insns = (uintptr_t) insns,
404 .license = (uintptr_t) "GPL",
406 .log_size = sizeof(log_buf),
407 .log_buf = (uintptr_t) log_buf,
408 .kern_version = 0xcafef00d,
411 static const unsigned int offset =
412 offsetofend(union bpf_attr, prog_flags);
413 const unsigned long addr = eop - offset;
415 memcpy((void *) addr, &attr, offset);
420 print_BPF_PROG_LOAD_attr(const unsigned long addr)
422 printf("prog_type=BPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=%u, insns=%p"
423 ", license=\"GPL\", log_level=42, log_size=4096, log_buf=%p"
424 ", kern_version=%u, prog_flags=BPF_F_STRICT_ALIGNMENT",
425 (unsigned int) ARRAY_SIZE(insns), insns,
426 log_buf, 0xcafef00d);
429 # endif /* HAVE_UNION_BPF_ATTR_PROG_FLAGS */
432 * bpf() syscall and its first six commands were introduced in Linux kernel
433 * 3.18. Some additional commands were added afterwards, so we need to take
434 * precautions to make sure the tests compile.
436 * BPF_OBJ_PIN and BPF_OBJ_GET commands appear in kernel 4.4.
438 # ifdef HAVE_UNION_BPF_ATTR_BPF_FD
441 init_BPF_OBJ_PIN_first(const unsigned long eop)
443 static const union bpf_attr attr = {};
444 static const unsigned int offset = sizeof(attr.pathname);
445 const unsigned long addr = eop - offset;
447 memcpy((void *) addr, &attr.pathname, offset);
452 print_BPF_OBJ_PIN_first(const unsigned long addr)
455 printf("pathname=NULL, bpf_fd=0");
459 init_BPF_OBJ_PIN_attr(const unsigned long eop)
461 const union bpf_attr attr = {
462 .pathname = (uintptr_t) "/sys/fs/bpf/foo/bar",
465 static const unsigned int offset =
466 offsetofend(union bpf_attr, bpf_fd);
467 const unsigned long addr = eop - offset;
469 memcpy((void *) addr, &attr, offset);
474 print_BPF_OBJ_PIN_attr(const unsigned long addr)
476 printf("pathname=\"/sys/fs/bpf/foo/bar\", bpf_fd=-1");
479 # define init_BPF_OBJ_GET_first init_BPF_OBJ_PIN_first
480 # define print_BPF_OBJ_GET_first print_BPF_OBJ_PIN_first
481 # define init_BPF_OBJ_GET_attr init_BPF_OBJ_PIN_attr
482 # define print_BPF_OBJ_GET_attr print_BPF_OBJ_PIN_attr
484 # endif /* HAVE_UNION_BPF_ATTR_BPF_FD */
486 /* BPF_PROG_ATTACH and BPF_PROG_DETACH commands appear in kernel 4.10. */
487 # ifdef HAVE_UNION_BPF_ATTR_ATTACH_FLAGS
490 init_BPF_PROG_ATTACH_first(const unsigned long eop)
492 static const union bpf_attr attr = { .target_fd = -1 };
493 static const unsigned int offset = sizeof(attr.target_fd);
494 const unsigned long addr = eop - offset;
496 memcpy((void *) addr, &attr.target_fd, offset);
501 print_BPF_PROG_ATTACH_first(const unsigned long addr)
503 printf("target_fd=-1, attach_bpf_fd=0"
504 ", attach_type=BPF_CGROUP_INET_INGRESS, attach_flags=0");
508 init_BPF_PROG_ATTACH_attr(const unsigned long eop)
510 static const union bpf_attr attr = {
516 static const unsigned int offset =
517 offsetofend(union bpf_attr, attach_flags);
518 const unsigned long addr = eop - offset;
520 memcpy((void *) addr, &attr, offset);
525 print_BPF_PROG_ATTACH_attr(const unsigned long addr)
527 printf("target_fd=-1, attach_bpf_fd=-2"
528 ", attach_type=BPF_CGROUP_INET_SOCK_CREATE"
529 ", attach_flags=BPF_F_ALLOW_OVERRIDE");
532 # define init_BPF_PROG_DETACH_first init_BPF_PROG_ATTACH_first
535 init_BPF_PROG_DETACH_attr(const unsigned long eop)
537 static const union bpf_attr attr = {
541 static const unsigned int offset =
542 offsetofend(union bpf_attr, attach_type);
543 const unsigned long addr = eop - offset;
545 memcpy((void *) addr, &attr, offset);
551 print_BPF_PROG_DETACH_first(const unsigned long addr)
553 printf("target_fd=-1, attach_type=BPF_CGROUP_INET_INGRESS");
557 print_BPF_PROG_DETACH_attr(const unsigned long addr)
559 printf("target_fd=-1, attach_type=BPF_CGROUP_INET_SOCK_CREATE");
562 # endif /* HAVE_UNION_BPF_ATTR_ATTACH_FLAGS */
567 page_size = get_page_size();
568 end_of_page = (unsigned long) tail_alloc(1) + 1;
570 # ifdef HAVE_UNION_BPF_ATTR_NUMA_NODE
571 TEST_BPF(BPF_MAP_CREATE);
574 # ifdef HAVE_UNION_BPF_ATTR_FLAGS
575 TEST_BPF(BPF_MAP_LOOKUP_ELEM);
576 TEST_BPF(BPF_MAP_UPDATE_ELEM);
577 TEST_BPF(BPF_MAP_DELETE_ELEM);
578 TEST_BPF(BPF_MAP_GET_NEXT_KEY);
581 # ifdef HAVE_UNION_BPF_ATTR_PROG_FLAGS
582 TEST_BPF(BPF_PROG_LOAD);
585 # ifdef HAVE_UNION_BPF_ATTR_BPF_FD
586 TEST_BPF(BPF_OBJ_PIN);
587 TEST_BPF(BPF_OBJ_GET);
590 # ifdef HAVE_UNION_BPF_ATTR_ATTACH_FLAGS
591 TEST_BPF(BPF_PROG_ATTACH);
592 TEST_BPF(BPF_PROG_DETACH);
595 sys_bpf(0xfacefeed, end_of_page, 40);
596 printf("bpf(0xfacefeed /* BPF_??? */, %#lx, 40) = %s\n",
597 end_of_page, errstr);
599 puts("+++ exited with 0 +++");
605 SKIP_MAIN_UNDEFINED("__NR_bpf && HAVE_UNION_BPF_ATTR_*")