Dmitry V. Levin
805d6ea570
Print union bpf_attr.value field of BPF_MAP_LOOKUP_ELEM command and union bpf_attr.next_key field of BPF_MAP_GET_NEXT_KEY command on entering syscall. These fields are addresses specified to the kernel from userspace. The amount of data written by the kernel to these addresses is specified at the map creation time by BPF_MAP_CREATE command and is not available at this point. * bpf.c (decode_BPF_MAP_LOOKUP_ELEM): Print union bpf_attr.value on entering syscall. (decode_BPF_MAP_GET_NEXT_KEY): Print union bpf_attr.next_key on entering syscall. (bpf_map_io): Remove. * tests/bpf.c (print_BPF_MAP_DELETE_ELEM_first, print_BPF_MAP_DELETE_ELEM_attr, print_BPF_MAP_GET_NEXT_KEY_first, print_BPF_MAP_GET_NEXT_KEY_attr): Replace macro redirects with new functions. (print_BPF_MAP_LOOKUP_ELEM_first, print_BPF_MAP_LOOKUP_ELEM_attr,
606 lines
16 KiB
C
606 lines
16 KiB
C
/*
|
|
* 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_INNER_MAP_FD \
|
|
|| defined HAVE_UNION_BPF_ATTR_PROG_FLAGS)
|
|
|
|
# include <stddef.h>
|
|
# include <stdio.h>
|
|
# include <stdint.h>
|
|
# include <string.h>
|
|
# include <unistd.h>
|
|
# include <linux/bpf.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_INNER_MAP_FD
|
|
|
|
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 = 1,
|
|
.inner_map_fd = -1
|
|
};
|
|
static const unsigned int offset =
|
|
offsetofend(union bpf_attr, inner_map_fd);
|
|
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, inner_map_fd=-1");
|
|
}
|
|
|
|
# endif /* HAVE_UNION_BPF_ATTR_INNER_MAP_FD */
|
|
|
|
# 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 */
|
|
|
|
int
|
|
main(void)
|
|
{
|
|
page_size = get_page_size();
|
|
end_of_page = (unsigned long) tail_alloc(1) + 1;
|
|
|
|
# ifdef HAVE_UNION_BPF_ATTR_INNER_MAP_FD
|
|
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
|
|
|
|
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
|