blob: 3f963fa3f009e7dfcaee396e0dc5599a329e548f [file] [log] [blame]
/*
* Check bpf syscall decoding.
*
* Copyright (c) 2015-2017 Dmitry V. Levin <ldv@altlinux.org>
* 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 <asm/unistd.h>
#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_INFO_INFO \
|| 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 <stddef.h>
# include <stdio.h>
# include <stdint.h>
# include <string.h>
# include <unistd.h>
# include <linux/bpf.h>
# 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. */
#define DEF_BPF_INIT_FIRST(cmd_, field_, value_) \
static unsigned int \
init_ ## cmd_ ## _first(const unsigned long eop) \
{ \
static const union bpf_attr attr = { .field_ = value_ };\
static const unsigned int offset = sizeof(attr.field_); \
const unsigned long addr = eop - offset; \
\
memcpy((void *) addr, &attr.field_, offset); \
return offset; \
} \
/* End of DEF_INIT_FIRST definition. */
# ifdef HAVE_UNION_BPF_ATTR_NUMA_NODE
DEF_BPF_INIT_FIRST(BPF_MAP_CREATE, map_type, 2)
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
DEF_BPF_INIT_FIRST(BPF_MAP_LOOKUP_ELEM, map_fd, -1)
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
DEF_BPF_INIT_FIRST(BPF_PROG_LOAD, prog_type, 1)
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
DEF_BPF_INIT_FIRST(BPF_OBJ_PIN, pathname, 0)
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
DEF_BPF_INIT_FIRST(BPF_PROG_ATTACH, target_fd, -1)
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
DEF_BPF_INIT_FIRST(BPF_PROG_TEST_RUN, test.prog_fd, -1)
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
DEF_BPF_INIT_FIRST(BPF_PROG_GET_NEXT_ID, start_id, 0xdeadbeef)
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 */
# ifdef HAVE_UNION_BPF_ATTR_INFO_INFO
DEF_BPF_INIT_FIRST(BPF_OBJ_GET_INFO_BY_FD, info.bpf_fd, -1)
static void
print_BPF_OBJ_GET_INFO_BY_FD_first(const unsigned long addr)
{
printf("info={bpf_fd=-1, info_len=0, info=0}");
}
static const union bpf_attr sample_BPF_OBJ_GET_INFO_BY_FD_attr = {
.info = {
.bpf_fd = -1,
.info_len = 0xdeadbeef,
.info = (uint64_t) 0xfacefeedbadc0ded
}
};
static unsigned int
init_BPF_OBJ_GET_INFO_BY_FD_attr(const unsigned long eop)
{
static const unsigned int offset =
offsetofend(union bpf_attr, info);
const unsigned long addr = eop - offset;
memcpy((void *) addr, &sample_BPF_OBJ_GET_INFO_BY_FD_attr, offset);
return offset;
}
static void
print_BPF_OBJ_GET_INFO_BY_FD_attr(const unsigned long addr)
{
PRINT_FIELD_D("info={", sample_BPF_OBJ_GET_INFO_BY_FD_attr.info, bpf_fd);
PRINT_FIELD_U(", ", sample_BPF_OBJ_GET_INFO_BY_FD_attr.info, info_len);
PRINT_FIELD_X(", ", sample_BPF_OBJ_GET_INFO_BY_FD_attr.info, info);
printf("}");
}
# endif /* HAVE_UNION_BPF_ATTR_INFO_INFO */
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
# ifdef HAVE_UNION_BPF_ATTR_INFO_INFO
TEST_BPF(BPF_OBJ_GET_INFO_BY_FD);
# 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