/* * Check bpf syscall decoding. * * Copyright (c) 2015-2017 Dmitry V. Levin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "tests.h" #include #if defined __NR_bpf \ && (defined HAVE_UNION_BPF_ATTR_ATTACH_FLAGS \ || defined HAVE_UNION_BPF_ATTR_BPF_FD \ || defined HAVE_UNION_BPF_ATTR_FLAGS \ || defined HAVE_UNION_BPF_ATTR_NEXT_ID \ || defined HAVE_UNION_BPF_ATTR_NUMA_NODE \ || defined HAVE_UNION_BPF_ATTR_PROG_FLAGS \ || defined HAVE_UNION_BPF_ATTR_TEST_DURATION) # include # include # include # include # include # include # include "print_fields.h" static const kernel_ulong_t long_bits = (kernel_ulong_t) 0xfacefeed00000000ULL; static const char *errstr; static unsigned int sizeof_attr = sizeof(union bpf_attr); static unsigned int page_size; static unsigned long end_of_page; static long sys_bpf(kernel_ulong_t cmd, kernel_ulong_t attr, kernel_ulong_t size) { long rc = syscall(__NR_bpf, cmd, attr, size); errstr = sprintrc(rc); return rc; } # if VERBOSE # define print_extra_data(addr_, size_) print_quoted_hex((addr_), (size_)) # else # define print_extra_data(addr_, size_) printf("...") #endif # define TEST_BPF_(cmd_, cmd_str_, \ init_first_, print_first_, \ init_attr_, print_attr_) \ do { \ /* zero addr */ \ sys_bpf(cmd_, 0, long_bits | sizeof(union bpf_attr)); \ printf("bpf(%s, NULL, %u) = %s\n", \ cmd_str_, sizeof_attr, errstr); \ \ /* zero size */ \ unsigned long addr = end_of_page - sizeof_attr; \ sys_bpf(cmd_, addr, long_bits); \ printf("bpf(%s, %#lx, 0) = %s\n", \ cmd_str_, addr, errstr); \ \ /* the first field only */ \ unsigned int offset = init_first_(end_of_page); \ addr = end_of_page - offset; \ sys_bpf(cmd_, addr, offset); \ printf("bpf(%s, {", cmd_str_); \ print_first_(addr); \ printf("}, %u) = %s\n", offset, errstr); \ \ /* efault after the first field */ \ sys_bpf(cmd_, addr, offset + 1); \ printf("bpf(%s, %#lx, %u) = %s\n", \ cmd_str_, addr, offset + 1, errstr); \ \ /* the relevant part of union bpf_attr */ \ offset = init_attr_(end_of_page); \ addr = end_of_page - offset; \ sys_bpf(cmd_, addr, offset); \ printf("bpf(%s, {", cmd_str_); \ print_attr_(addr); \ printf("}, %u) = %s\n", offset, errstr); \ \ /* short read of the relevant part of union bpf_attr */ \ sys_bpf(cmd_, addr + 1, offset); \ printf("bpf(%s, %#lx, %u) = %s\n", \ cmd_str_, addr + 1, offset, errstr); \ \ if (offset < sizeof_attr) { \ /* short read of the whole union bpf_attr */ \ memmove((void *) end_of_page - sizeof_attr + 1, \ (void *) addr, offset); \ addr = end_of_page - sizeof_attr + 1; \ memset((void *) addr + offset, 0, \ sizeof_attr - offset - 1); \ sys_bpf(cmd_, addr, sizeof_attr); \ printf("bpf(%s, %#lx, %u) = %s\n", \ cmd_str_, addr, sizeof_attr, errstr); \ \ /* the whole union bpf_attr */ \ memmove((void *) end_of_page - sizeof_attr, \ (void *) addr, offset); \ addr = end_of_page - sizeof_attr; \ memset((void *) addr + offset, 0, \ sizeof_attr - offset); \ sys_bpf(cmd_, addr, sizeof_attr); \ printf("bpf(%s, {", cmd_str_); \ print_attr_(addr); \ printf("}, %u) = %s\n", sizeof_attr, errstr); \ \ /* non-zero bytes after the relevant part */ \ fill_memory_ex((void *) addr + offset, \ sizeof_attr - offset, '0', 10); \ sys_bpf(cmd_, addr, sizeof_attr); \ printf("bpf(%s, {", cmd_str_); \ print_attr_(addr); \ printf(", "); \ print_extra_data((void *) addr + offset, \ sizeof_attr - offset); \ printf("}, %u) = %s\n", sizeof_attr, errstr); \ } \ \ /* short read of the whole page */ \ memmove((void *) end_of_page - page_size + 1, \ (void *) addr, offset); \ addr = end_of_page - page_size + 1; \ memset((void *) addr + offset, 0, \ page_size - offset - 1); \ sys_bpf(cmd_, addr, page_size); \ printf("bpf(%s, %#lx, %u) = %s\n", \ cmd_str_, addr, page_size, errstr); \ \ /* the whole page */ \ memmove((void *) end_of_page - page_size, \ (void *) addr, offset); \ addr = end_of_page - page_size; \ memset((void *) addr + offset, 0, page_size - offset); \ sys_bpf(cmd_, addr, page_size); \ printf("bpf(%s, {", cmd_str_); \ print_attr_(addr); \ printf("}, %u) = %s\n", page_size, errstr); \ \ /* non-zero bytes after the whole union bpf_attr */ \ fill_memory_ex((void *) addr + offset, \ page_size - offset, '0', 10); \ sys_bpf(cmd_, addr, page_size); \ printf("bpf(%s, {", cmd_str_); \ print_attr_(addr); \ printf(", "); \ print_extra_data((void *) addr + offset, \ page_size - offset); \ printf("}, %u) = %s\n", page_size, errstr); \ \ /* more than a page */ \ sys_bpf(cmd_, addr, page_size + 1); \ printf("bpf(%s, %#lx, %u) = %s\n", \ cmd_str_, addr, page_size + 1, errstr); \ } while (0) \ /* End of TEST_BPF_ definition. */ # define TEST_BPF(cmd_) \ TEST_BPF_((cmd_), #cmd_, \ init_ ## cmd_ ## _first, print_ ## cmd_ ## _first, \ init_ ## cmd_ ## _attr, print_ ## cmd_ ## _attr) \ /* End of TEST_BPF definition. */ # ifdef HAVE_UNION_BPF_ATTR_NUMA_NODE static unsigned int init_BPF_MAP_CREATE_first(const unsigned long eop) { static const union bpf_attr attr = { .map_type = 2 }; static const unsigned int offset = sizeof(attr.map_type); const unsigned long addr = eop - offset; memcpy((void *) addr, &attr.map_type, offset); return offset; } static void print_BPF_MAP_CREATE_first(const unsigned long addr) { printf("map_type=BPF_MAP_TYPE_ARRAY, key_size=0, value_size=0" ", max_entries=0, map_flags=0, inner_map_fd=0"); } static unsigned int init_BPF_MAP_CREATE_attr(const unsigned long eop) { static const union bpf_attr attr = { .map_type = 1, .key_size = 4, .value_size = 8, .max_entries = 256, .map_flags = 7, .inner_map_fd = -1, .numa_node = 42 }; static const unsigned int offset = offsetofend(union bpf_attr, numa_node); const unsigned long addr = eop - offset; memcpy((void *) addr, &attr, offset); return offset; } static void print_BPF_MAP_CREATE_attr(const unsigned long addr) { printf("map_type=BPF_MAP_TYPE_HASH, key_size=4" ", value_size=8, max_entries=256" ", map_flags=BPF_F_NO_PREALLOC|BPF_F_NO_COMMON_LRU" "|BPF_F_NUMA_NODE, inner_map_fd=-1, numa_node=42"); } # endif /* HAVE_UNION_BPF_ATTR_NUMA_NODE */ # ifdef HAVE_UNION_BPF_ATTR_FLAGS static unsigned int init_BPF_MAP_LOOKUP_ELEM_first(const unsigned long eop) { static const union bpf_attr attr = { .map_fd = -1 }; static const unsigned int offset = sizeof(attr.map_fd); const unsigned long addr = eop - offset; memcpy((void *) addr, &attr.map_fd, offset); return offset; } static void print_BPF_MAP_LOOKUP_ELEM_first(const unsigned long addr) { printf("map_fd=-1, key=0, value=0"); } static unsigned int init_BPF_MAP_LOOKUP_ELEM_attr(const unsigned long eop) { static const union bpf_attr attr = { .map_fd = -1, .key = 0xdeadbeef, .value = 0xbadc0ded }; static const unsigned int offset = offsetofend(union bpf_attr, value); const unsigned long addr = eop - offset; memcpy((void *) addr, &attr, offset); return offset; } static void print_BPF_MAP_LOOKUP_ELEM_attr(const unsigned long addr) { printf("map_fd=-1, key=0xdeadbeef, value=0xbadc0ded"); } # define init_BPF_MAP_UPDATE_ELEM_first init_BPF_MAP_LOOKUP_ELEM_first static void print_BPF_MAP_UPDATE_ELEM_first(const unsigned long addr) { printf("map_fd=-1, key=0, value=0, flags=BPF_ANY"); } static unsigned int init_BPF_MAP_UPDATE_ELEM_attr(const unsigned long eop) { static const union bpf_attr attr = { .map_fd = -1, .key = 0xdeadbeef, .value = 0xbadc0ded, .flags = 2 }; static const unsigned int offset = offsetofend(union bpf_attr, flags); const unsigned long addr = eop - offset; memcpy((void *) addr, &attr, offset); return offset; } static void print_BPF_MAP_UPDATE_ELEM_attr(const unsigned long addr) { printf("map_fd=-1, key=0xdeadbeef, value=0xbadc0ded, flags=BPF_EXIST"); } # define init_BPF_MAP_DELETE_ELEM_first init_BPF_MAP_LOOKUP_ELEM_first static void print_BPF_MAP_DELETE_ELEM_first(const unsigned long addr) { printf("map_fd=-1, key=0"); } static unsigned int init_BPF_MAP_DELETE_ELEM_attr(const unsigned long eop) { static const union bpf_attr attr = { .map_fd = -1, .key = 0xdeadbeef }; static const unsigned int offset = offsetofend(union bpf_attr, key); const unsigned long addr = eop - offset; memcpy((void *) addr, &attr, offset); return offset; } static void print_BPF_MAP_DELETE_ELEM_attr(const unsigned long addr) { printf("map_fd=-1, key=0xdeadbeef"); } # define init_BPF_MAP_GET_NEXT_KEY_first init_BPF_MAP_LOOKUP_ELEM_first static void print_BPF_MAP_GET_NEXT_KEY_first(const unsigned long addr) { printf("map_fd=-1, key=0, next_key=0"); } static unsigned int init_BPF_MAP_GET_NEXT_KEY_attr(const unsigned long eop) { static const union bpf_attr attr = { .map_fd = -1, .key = 0xdeadbeef, .next_key = 0xbadc0ded }; static const unsigned int offset = offsetofend(union bpf_attr, next_key); const unsigned long addr = eop - offset; memcpy((void *) addr, &attr, offset); return offset; } static void print_BPF_MAP_GET_NEXT_KEY_attr(const unsigned long addr) { printf("map_fd=-1, key=0xdeadbeef, next_key=0xbadc0ded"); } # endif /* HAVE_UNION_BPF_ATTR_FLAGS */ # ifdef HAVE_UNION_BPF_ATTR_PROG_FLAGS static unsigned int init_BPF_PROG_LOAD_first(const unsigned long eop) { static const union bpf_attr attr = { .prog_type = 1 }; static const unsigned int offset = sizeof(attr.prog_type); const unsigned long addr = eop - offset; memcpy((void *) addr, &attr.prog_type, offset); return offset; } static void print_BPF_PROG_LOAD_first(const unsigned long addr) { printf("prog_type=BPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=0, insns=0" ", license=NULL, log_level=0, log_size=0, log_buf=0" ", kern_version=0, prog_flags=0"); } static const struct bpf_insn insns[] = { { .code = BPF_JMP | BPF_EXIT } }; static char log_buf[4096]; static unsigned int init_BPF_PROG_LOAD_attr(const unsigned long eop) { const union bpf_attr attr = { .prog_type = 1, .insn_cnt = ARRAY_SIZE(insns), .insns = (uintptr_t) insns, .license = (uintptr_t) "GPL", .log_level = 42, .log_size = sizeof(log_buf), .log_buf = (uintptr_t) log_buf, .kern_version = 0xcafef00d, .prog_flags = 1 }; static const unsigned int offset = offsetofend(union bpf_attr, prog_flags); const unsigned long addr = eop - offset; memcpy((void *) addr, &attr, offset); return offset; } static void print_BPF_PROG_LOAD_attr(const unsigned long addr) { printf("prog_type=BPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=%u, insns=%p" ", license=\"GPL\", log_level=42, log_size=4096, log_buf=%p" ", kern_version=%u, prog_flags=BPF_F_STRICT_ALIGNMENT", (unsigned int) ARRAY_SIZE(insns), insns, log_buf, 0xcafef00d); } # endif /* HAVE_UNION_BPF_ATTR_PROG_FLAGS */ /* * bpf() syscall and its first six commands were introduced in Linux kernel * 3.18. Some additional commands were added afterwards, so we need to take * precautions to make sure the tests compile. * * BPF_OBJ_PIN and BPF_OBJ_GET commands appear in kernel 4.4. */ # ifdef HAVE_UNION_BPF_ATTR_BPF_FD static unsigned int init_BPF_OBJ_PIN_first(const unsigned long eop) { static const union bpf_attr attr = {}; static const unsigned int offset = sizeof(attr.pathname); const unsigned long addr = eop - offset; memcpy((void *) addr, &attr.pathname, offset); return offset; } static void print_BPF_OBJ_PIN_first(const unsigned long addr) { printf("pathname=NULL, bpf_fd=0"); } static unsigned int init_BPF_OBJ_PIN_attr(const unsigned long eop) { const union bpf_attr attr = { .pathname = (uintptr_t) "/sys/fs/bpf/foo/bar", .bpf_fd = -1 }; static const unsigned int offset = offsetofend(union bpf_attr, bpf_fd); const unsigned long addr = eop - offset; memcpy((void *) addr, &attr, offset); return offset; } static void print_BPF_OBJ_PIN_attr(const unsigned long addr) { printf("pathname=\"/sys/fs/bpf/foo/bar\", bpf_fd=-1"); } # define init_BPF_OBJ_GET_first init_BPF_OBJ_PIN_first # define print_BPF_OBJ_GET_first print_BPF_OBJ_PIN_first # define init_BPF_OBJ_GET_attr init_BPF_OBJ_PIN_attr # define print_BPF_OBJ_GET_attr print_BPF_OBJ_PIN_attr # endif /* HAVE_UNION_BPF_ATTR_BPF_FD */ /* BPF_PROG_ATTACH and BPF_PROG_DETACH commands appear in kernel 4.10. */ # ifdef HAVE_UNION_BPF_ATTR_ATTACH_FLAGS static unsigned int init_BPF_PROG_ATTACH_first(const unsigned long eop) { static const union bpf_attr attr = { .target_fd = -1 }; static const unsigned int offset = sizeof(attr.target_fd); const unsigned long addr = eop - offset; memcpy((void *) addr, &attr.target_fd, offset); return offset; } static void print_BPF_PROG_ATTACH_first(const unsigned long addr) { printf("target_fd=-1, attach_bpf_fd=0" ", attach_type=BPF_CGROUP_INET_INGRESS, attach_flags=0"); } static unsigned int init_BPF_PROG_ATTACH_attr(const unsigned long eop) { static const union bpf_attr attr = { .target_fd = -1, .attach_bpf_fd = -2, .attach_type = 2, .attach_flags = 1 }; static const unsigned int offset = offsetofend(union bpf_attr, attach_flags); const unsigned long addr = eop - offset; memcpy((void *) addr, &attr, offset); return offset; } static void print_BPF_PROG_ATTACH_attr(const unsigned long addr) { printf("target_fd=-1, attach_bpf_fd=-2" ", attach_type=BPF_CGROUP_INET_SOCK_CREATE" ", attach_flags=BPF_F_ALLOW_OVERRIDE"); } # define init_BPF_PROG_DETACH_first init_BPF_PROG_ATTACH_first static unsigned int init_BPF_PROG_DETACH_attr(const unsigned long eop) { static const union bpf_attr attr = { .target_fd = -1, .attach_type = 2 }; static const unsigned int offset = offsetofend(union bpf_attr, attach_type); const unsigned long addr = eop - offset; memcpy((void *) addr, &attr, offset); return offset; } static void print_BPF_PROG_DETACH_first(const unsigned long addr) { printf("target_fd=-1, attach_type=BPF_CGROUP_INET_INGRESS"); } static void print_BPF_PROG_DETACH_attr(const unsigned long addr) { printf("target_fd=-1, attach_type=BPF_CGROUP_INET_SOCK_CREATE"); } # endif /* HAVE_UNION_BPF_ATTR_ATTACH_FLAGS */ /* BPF_PROG_TEST_RUN command appears in kernel 4.12. */ # ifdef HAVE_UNION_BPF_ATTR_TEST_DURATION static unsigned int init_BPF_PROG_TEST_RUN_first(const unsigned long eop) { static const union bpf_attr attr = { .test.prog_fd = -1 }; static const unsigned int offset = sizeof(attr.test.prog_fd); const unsigned long addr = eop - offset; memcpy((void *) addr, &attr.test.prog_fd, offset); return offset; } static void print_BPF_PROG_TEST_RUN_first(const unsigned long addr) { printf("test={prog_fd=-1, retval=0, data_size_in=0, data_size_out=0" ", data_in=0, data_out=0, repeat=0, duration=0}"); } static const union bpf_attr sample_BPF_PROG_TEST_RUN_attr = { .test = { .prog_fd = -1, .retval = 0xfac1fed2, .data_size_in = 0xfac3fed4, .data_size_out = 0xfac5fed6, .data_in = (uint64_t) 0xfacef11dbadc2ded, .data_out = (uint64_t) 0xfacef33dbadc4ded, .repeat = 0xfac7fed8, .duration = 0xfac9feda } }; static unsigned int init_BPF_PROG_TEST_RUN_attr(const unsigned long eop) { static const unsigned int offset = offsetofend(union bpf_attr, test); const unsigned long addr = eop - offset; memcpy((void *) addr, &sample_BPF_PROG_TEST_RUN_attr, offset); return offset; } static void print_BPF_PROG_TEST_RUN_attr(const unsigned long addr) { PRINT_FIELD_D("test={", sample_BPF_PROG_TEST_RUN_attr.test, prog_fd); PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, retval); PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_size_in); PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_size_out); PRINT_FIELD_X(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_in); PRINT_FIELD_X(", ", sample_BPF_PROG_TEST_RUN_attr.test, data_out); PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, repeat); PRINT_FIELD_U(", ", sample_BPF_PROG_TEST_RUN_attr.test, duration); printf("}"); } # endif /* HAVE_UNION_BPF_ATTR_TEST_DURATION */ # ifdef HAVE_UNION_BPF_ATTR_NEXT_ID static unsigned int init_BPF_PROG_GET_NEXT_ID_first(const unsigned long eop) { static const union bpf_attr attr = { .start_id = 0xdeadbeef }; static const unsigned int offset = sizeof(attr.start_id); const unsigned long addr = eop - offset; memcpy((void *) addr, &attr.start_id, offset); return offset; } static void print_BPF_PROG_GET_NEXT_ID_first(const unsigned long addr) { printf("start_id=%u, next_id=0", 0xdeadbeef); } static unsigned int init_BPF_PROG_GET_NEXT_ID_attr(const unsigned long eop) { static const union bpf_attr attr = { .start_id = 0xbadc0ded, .next_id = 0xcafef00d }; static const unsigned int offset = offsetofend(union bpf_attr, next_id); const unsigned long addr = eop - offset; memcpy((void *) addr, &attr, offset); return offset; } static void print_BPF_PROG_GET_NEXT_ID_attr(const unsigned long addr) { printf("start_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d); } # define init_BPF_MAP_GET_NEXT_ID_first init_BPF_PROG_GET_NEXT_ID_first # define print_BPF_MAP_GET_NEXT_ID_first print_BPF_PROG_GET_NEXT_ID_first # define init_BPF_MAP_GET_NEXT_ID_attr init_BPF_PROG_GET_NEXT_ID_attr # define print_BPF_MAP_GET_NEXT_ID_attr print_BPF_PROG_GET_NEXT_ID_attr # define init_BPF_PROG_GET_FD_BY_ID_first init_BPF_PROG_GET_NEXT_ID_first # define init_BPF_PROG_GET_FD_BY_ID_attr init_BPF_PROG_GET_NEXT_ID_attr static void print_BPF_PROG_GET_FD_BY_ID_first(const unsigned long addr) { printf("prog_id=%u, next_id=0", 0xdeadbeef); } static void print_BPF_PROG_GET_FD_BY_ID_attr(const unsigned long addr) { printf("prog_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d); } # define init_BPF_MAP_GET_FD_BY_ID_first init_BPF_PROG_GET_NEXT_ID_first # define init_BPF_MAP_GET_FD_BY_ID_attr init_BPF_PROG_GET_NEXT_ID_attr static void print_BPF_MAP_GET_FD_BY_ID_first(const unsigned long addr) { printf("map_id=%u, next_id=0", 0xdeadbeef); } static void print_BPF_MAP_GET_FD_BY_ID_attr(const unsigned long addr) { printf("map_id=%u, next_id=%u", 0xbadc0ded, 0xcafef00d); } # endif /* HAVE_UNION_BPF_ATTR_NEXT_ID */ int main(void) { page_size = get_page_size(); end_of_page = (unsigned long) tail_alloc(1) + 1; # ifdef HAVE_UNION_BPF_ATTR_NUMA_NODE TEST_BPF(BPF_MAP_CREATE); # endif # ifdef HAVE_UNION_BPF_ATTR_FLAGS TEST_BPF(BPF_MAP_LOOKUP_ELEM); TEST_BPF(BPF_MAP_UPDATE_ELEM); TEST_BPF(BPF_MAP_DELETE_ELEM); TEST_BPF(BPF_MAP_GET_NEXT_KEY); # endif # ifdef HAVE_UNION_BPF_ATTR_PROG_FLAGS TEST_BPF(BPF_PROG_LOAD); # endif # ifdef HAVE_UNION_BPF_ATTR_BPF_FD TEST_BPF(BPF_OBJ_PIN); TEST_BPF(BPF_OBJ_GET); # endif # ifdef HAVE_UNION_BPF_ATTR_ATTACH_FLAGS TEST_BPF(BPF_PROG_ATTACH); TEST_BPF(BPF_PROG_DETACH); # endif # ifdef HAVE_UNION_BPF_ATTR_TEST_DURATION TEST_BPF(BPF_PROG_TEST_RUN); # endif # ifdef HAVE_UNION_BPF_ATTR_NEXT_ID TEST_BPF(BPF_PROG_GET_NEXT_ID); TEST_BPF(BPF_MAP_GET_NEXT_ID); TEST_BPF(BPF_PROG_GET_FD_BY_ID); TEST_BPF(BPF_MAP_GET_FD_BY_ID); # endif sys_bpf(0xfacefeed, end_of_page, 40); printf("bpf(0xfacefeed /* BPF_??? */, %#lx, 40) = %s\n", end_of_page, errstr); puts("+++ exited with 0 +++"); return 0; } #else SKIP_MAIN_UNDEFINED("__NR_bpf && HAVE_UNION_BPF_ATTR_*") #endif