Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
Alexei Starovoitov says: ==================== pull-request: bpf-next 2019-11-02 The following pull-request contains BPF updates for your *net-next* tree. We've added 30 non-merge commits during the last 7 day(s) which contain a total of 41 files changed, 1864 insertions(+), 474 deletions(-). The main changes are: 1) Fix long standing user vs kernel access issue by introducing bpf_probe_read_user() and bpf_probe_read_kernel() helpers, from Daniel. 2) Accelerated xskmap lookup, from Björn and Maciej. 3) Support for automatic map pinning in libbpf, from Toke. 4) Cleanup of BTF-enabled raw tracepoints, from Alexei. 5) Various fixes to libbpf and selftests. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -89,6 +89,9 @@ $(notdir $(TEST_GEN_PROGS) \
|
||||
$(OUTPUT)/urandom_read: urandom_read.c
|
||||
$(CC) -o $@ $< -Wl,--build-id
|
||||
|
||||
$(OUTPUT)/test_stub.o: test_stub.c
|
||||
$(CC) -c $(CFLAGS) -o $@ $<
|
||||
|
||||
BPFOBJ := $(OUTPUT)/libbpf.a
|
||||
|
||||
$(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/test_stub.o $(BPFOBJ)
|
||||
@@ -131,8 +134,13 @@ $(shell $(1) -v -E - </dev/null 2>&1 \
|
||||
| sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }')
|
||||
endef
|
||||
|
||||
# Determine target endianness.
|
||||
IS_LITTLE_ENDIAN = $(shell $(CC) -dM -E - </dev/null | \
|
||||
grep 'define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__')
|
||||
MENDIAN=$(if $(IS_LITTLE_ENDIAN),-mlittle-endian,-mbig-endian)
|
||||
|
||||
CLANG_SYS_INCLUDES = $(call get_sys_includes,$(CLANG))
|
||||
BPF_CFLAGS = -g -D__TARGET_ARCH_$(SRCARCH) \
|
||||
BPF_CFLAGS = -g -D__TARGET_ARCH_$(SRCARCH) $(MENDIAN) \
|
||||
-I. -I./include/uapi -I$(APIDIR) \
|
||||
-I$(BPFDIR) -I$(abspath $(OUTPUT)/../usr/include)
|
||||
|
||||
@@ -271,12 +279,8 @@ $(eval $(call DEFINE_TEST_RUNNER,test_progs,no_alu32))
|
||||
|
||||
# Define test_progs BPF-GCC-flavored test runner.
|
||||
ifneq ($(BPF_GCC),)
|
||||
IS_LITTLE_ENDIAN = $(shell $(CC) -dM -E - </dev/null | \
|
||||
grep 'define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__')
|
||||
MENDIAN=$(if $(IS_LITTLE_ENDIAN),-mlittle-endian,-mbig-endian)
|
||||
|
||||
TRUNNER_BPF_BUILD_RULE := GCC_BPF_BUILD_RULE
|
||||
TRUNNER_BPF_CFLAGS := $(BPF_CFLAGS) $(call get_sys_includes,gcc) $(MENDIAN)
|
||||
TRUNNER_BPF_CFLAGS := $(BPF_CFLAGS) $(call get_sys_includes,gcc)
|
||||
TRUNNER_BPF_LDFLAGS :=
|
||||
$(eval $(call DEFINE_TEST_RUNNER,test_progs,bpf_gcc))
|
||||
endif
|
||||
|
||||
210
tools/testing/selftests/bpf/prog_tests/pinning.c
Normal file
210
tools/testing/selftests/bpf/prog_tests/pinning.c
Normal file
@@ -0,0 +1,210 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <test_progs.h>
|
||||
|
||||
__u32 get_map_id(struct bpf_object *obj, const char *name)
|
||||
{
|
||||
struct bpf_map_info map_info = {};
|
||||
__u32 map_info_len, duration = 0;
|
||||
struct bpf_map *map;
|
||||
int err;
|
||||
|
||||
map_info_len = sizeof(map_info);
|
||||
|
||||
map = bpf_object__find_map_by_name(obj, name);
|
||||
if (CHECK(!map, "find map", "NULL map"))
|
||||
return 0;
|
||||
|
||||
err = bpf_obj_get_info_by_fd(bpf_map__fd(map),
|
||||
&map_info, &map_info_len);
|
||||
CHECK(err, "get map info", "err %d errno %d", err, errno);
|
||||
return map_info.id;
|
||||
}
|
||||
|
||||
void test_pinning(void)
|
||||
{
|
||||
const char *file_invalid = "./test_pinning_invalid.o";
|
||||
const char *custpinpath = "/sys/fs/bpf/custom/pinmap";
|
||||
const char *nopinpath = "/sys/fs/bpf/nopinmap";
|
||||
const char *nopinpath2 = "/sys/fs/bpf/nopinmap2";
|
||||
const char *custpath = "/sys/fs/bpf/custom";
|
||||
const char *pinpath = "/sys/fs/bpf/pinmap";
|
||||
const char *file = "./test_pinning.o";
|
||||
__u32 map_id, map_id2, duration = 0;
|
||||
struct stat statbuf = {};
|
||||
struct bpf_object *obj;
|
||||
struct bpf_map *map;
|
||||
int err;
|
||||
DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts,
|
||||
.pin_root_path = custpath,
|
||||
);
|
||||
|
||||
/* check that opening fails with invalid pinning value in map def */
|
||||
obj = bpf_object__open_file(file_invalid, NULL);
|
||||
err = libbpf_get_error(obj);
|
||||
if (CHECK(err != -EINVAL, "invalid open", "err %d errno %d\n", err, errno)) {
|
||||
obj = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* open the valid object file */
|
||||
obj = bpf_object__open_file(file, NULL);
|
||||
err = libbpf_get_error(obj);
|
||||
if (CHECK(err, "default open", "err %d errno %d\n", err, errno)) {
|
||||
obj = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = bpf_object__load(obj);
|
||||
if (CHECK(err, "default load", "err %d errno %d\n", err, errno))
|
||||
goto out;
|
||||
|
||||
/* check that pinmap was pinned */
|
||||
err = stat(pinpath, &statbuf);
|
||||
if (CHECK(err, "stat pinpath", "err %d errno %d\n", err, errno))
|
||||
goto out;
|
||||
|
||||
/* check that nopinmap was *not* pinned */
|
||||
err = stat(nopinpath, &statbuf);
|
||||
if (CHECK(!err || errno != ENOENT, "stat nopinpath",
|
||||
"err %d errno %d\n", err, errno))
|
||||
goto out;
|
||||
|
||||
/* check that nopinmap2 was *not* pinned */
|
||||
err = stat(nopinpath2, &statbuf);
|
||||
if (CHECK(!err || errno != ENOENT, "stat nopinpath2",
|
||||
"err %d errno %d\n", err, errno))
|
||||
goto out;
|
||||
|
||||
map_id = get_map_id(obj, "pinmap");
|
||||
if (!map_id)
|
||||
goto out;
|
||||
|
||||
bpf_object__close(obj);
|
||||
|
||||
obj = bpf_object__open_file(file, NULL);
|
||||
if (CHECK_FAIL(libbpf_get_error(obj))) {
|
||||
obj = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = bpf_object__load(obj);
|
||||
if (CHECK(err, "default load", "err %d errno %d\n", err, errno))
|
||||
goto out;
|
||||
|
||||
/* check that same map ID was reused for second load */
|
||||
map_id2 = get_map_id(obj, "pinmap");
|
||||
if (CHECK(map_id != map_id2, "check reuse",
|
||||
"err %d errno %d id %d id2 %d\n", err, errno, map_id, map_id2))
|
||||
goto out;
|
||||
|
||||
/* should be no-op to re-pin same map */
|
||||
map = bpf_object__find_map_by_name(obj, "pinmap");
|
||||
if (CHECK(!map, "find map", "NULL map"))
|
||||
goto out;
|
||||
|
||||
err = bpf_map__pin(map, NULL);
|
||||
if (CHECK(err, "re-pin map", "err %d errno %d\n", err, errno))
|
||||
goto out;
|
||||
|
||||
/* but error to pin at different location */
|
||||
err = bpf_map__pin(map, "/sys/fs/bpf/other");
|
||||
if (CHECK(!err, "pin map different", "err %d errno %d\n", err, errno))
|
||||
goto out;
|
||||
|
||||
/* unpin maps with a pin_path set */
|
||||
err = bpf_object__unpin_maps(obj, NULL);
|
||||
if (CHECK(err, "unpin maps", "err %d errno %d\n", err, errno))
|
||||
goto out;
|
||||
|
||||
/* and re-pin them... */
|
||||
err = bpf_object__pin_maps(obj, NULL);
|
||||
if (CHECK(err, "pin maps", "err %d errno %d\n", err, errno))
|
||||
goto out;
|
||||
|
||||
/* set pinning path of other map and re-pin all */
|
||||
map = bpf_object__find_map_by_name(obj, "nopinmap");
|
||||
if (CHECK(!map, "find map", "NULL map"))
|
||||
goto out;
|
||||
|
||||
err = bpf_map__set_pin_path(map, custpinpath);
|
||||
if (CHECK(err, "set pin path", "err %d errno %d\n", err, errno))
|
||||
goto out;
|
||||
|
||||
/* should only pin the one unpinned map */
|
||||
err = bpf_object__pin_maps(obj, NULL);
|
||||
if (CHECK(err, "pin maps", "err %d errno %d\n", err, errno))
|
||||
goto out;
|
||||
|
||||
/* check that nopinmap was pinned at the custom path */
|
||||
err = stat(custpinpath, &statbuf);
|
||||
if (CHECK(err, "stat custpinpath", "err %d errno %d\n", err, errno))
|
||||
goto out;
|
||||
|
||||
/* remove the custom pin path to re-test it with auto-pinning below */
|
||||
err = unlink(custpinpath);
|
||||
if (CHECK(err, "unlink custpinpath", "err %d errno %d\n", err, errno))
|
||||
goto out;
|
||||
|
||||
err = rmdir(custpath);
|
||||
if (CHECK(err, "rmdir custpindir", "err %d errno %d\n", err, errno))
|
||||
goto out;
|
||||
|
||||
bpf_object__close(obj);
|
||||
|
||||
/* open the valid object file again */
|
||||
obj = bpf_object__open_file(file, NULL);
|
||||
err = libbpf_get_error(obj);
|
||||
if (CHECK(err, "default open", "err %d errno %d\n", err, errno)) {
|
||||
obj = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* swap pin paths of the two maps */
|
||||
bpf_object__for_each_map(map, obj) {
|
||||
if (!strcmp(bpf_map__name(map), "nopinmap"))
|
||||
err = bpf_map__set_pin_path(map, pinpath);
|
||||
else if (!strcmp(bpf_map__name(map), "pinmap"))
|
||||
err = bpf_map__set_pin_path(map, NULL);
|
||||
else
|
||||
continue;
|
||||
|
||||
if (CHECK(err, "set pin path", "err %d errno %d\n", err, errno))
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* should fail because of map parameter mismatch */
|
||||
err = bpf_object__load(obj);
|
||||
if (CHECK(err != -EINVAL, "param mismatch load", "err %d errno %d\n", err, errno))
|
||||
goto out;
|
||||
|
||||
bpf_object__close(obj);
|
||||
|
||||
/* test auto-pinning at custom path with open opt */
|
||||
obj = bpf_object__open_file(file, &opts);
|
||||
if (CHECK_FAIL(libbpf_get_error(obj))) {
|
||||
obj = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = bpf_object__load(obj);
|
||||
if (CHECK(err, "custom load", "err %d errno %d\n", err, errno))
|
||||
goto out;
|
||||
|
||||
/* check that pinmap was pinned at the custom path */
|
||||
err = stat(custpinpath, &statbuf);
|
||||
if (CHECK(err, "stat custpinpath", "err %d errno %d\n", err, errno))
|
||||
goto out;
|
||||
|
||||
out:
|
||||
unlink(pinpath);
|
||||
unlink(nopinpath);
|
||||
unlink(nopinpath2);
|
||||
unlink(custpinpath);
|
||||
rmdir(custpath);
|
||||
if (obj)
|
||||
bpf_object__close(obj);
|
||||
}
|
||||
78
tools/testing/selftests/bpf/prog_tests/probe_user.c
Normal file
78
tools/testing/selftests/bpf/prog_tests/probe_user.c
Normal file
@@ -0,0 +1,78 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <test_progs.h>
|
||||
|
||||
void test_probe_user(void)
|
||||
{
|
||||
#define kprobe_name "__sys_connect"
|
||||
const char *prog_name = "kprobe/" kprobe_name;
|
||||
const char *obj_file = "./test_probe_user.o";
|
||||
DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts, );
|
||||
int err, results_map_fd, sock_fd, duration = 0;
|
||||
struct sockaddr curr, orig, tmp;
|
||||
struct sockaddr_in *in = (struct sockaddr_in *)&curr;
|
||||
struct bpf_link *kprobe_link = NULL;
|
||||
struct bpf_program *kprobe_prog;
|
||||
struct bpf_object *obj;
|
||||
static const int zero = 0;
|
||||
|
||||
obj = bpf_object__open_file(obj_file, &opts);
|
||||
if (CHECK(IS_ERR(obj), "obj_open_file", "err %ld\n", PTR_ERR(obj)))
|
||||
return;
|
||||
|
||||
kprobe_prog = bpf_object__find_program_by_title(obj, prog_name);
|
||||
if (CHECK(!kprobe_prog, "find_probe",
|
||||
"prog '%s' not found\n", prog_name))
|
||||
goto cleanup;
|
||||
|
||||
err = bpf_object__load(obj);
|
||||
if (CHECK(err, "obj_load", "err %d\n", err))
|
||||
goto cleanup;
|
||||
|
||||
results_map_fd = bpf_find_map(__func__, obj, "test_pro.bss");
|
||||
if (CHECK(results_map_fd < 0, "find_bss_map",
|
||||
"err %d\n", results_map_fd))
|
||||
goto cleanup;
|
||||
|
||||
kprobe_link = bpf_program__attach_kprobe(kprobe_prog, false,
|
||||
kprobe_name);
|
||||
if (CHECK(IS_ERR(kprobe_link), "attach_kprobe",
|
||||
"err %ld\n", PTR_ERR(kprobe_link))) {
|
||||
kprobe_link = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
memset(&curr, 0, sizeof(curr));
|
||||
in->sin_family = AF_INET;
|
||||
in->sin_port = htons(5555);
|
||||
in->sin_addr.s_addr = inet_addr("255.255.255.255");
|
||||
memcpy(&orig, &curr, sizeof(curr));
|
||||
|
||||
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (CHECK(sock_fd < 0, "create_sock_fd", "err %d\n", sock_fd))
|
||||
goto cleanup;
|
||||
|
||||
connect(sock_fd, &curr, sizeof(curr));
|
||||
close(sock_fd);
|
||||
|
||||
err = bpf_map_lookup_elem(results_map_fd, &zero, &tmp);
|
||||
if (CHECK(err, "get_kprobe_res",
|
||||
"failed to get kprobe res: %d\n", err))
|
||||
goto cleanup;
|
||||
|
||||
in = (struct sockaddr_in *)&tmp;
|
||||
if (CHECK(memcmp(&tmp, &orig, sizeof(orig)), "check_kprobe_res",
|
||||
"wrong kprobe res from probe read: %s:%u\n",
|
||||
inet_ntoa(in->sin_addr), ntohs(in->sin_port)))
|
||||
goto cleanup;
|
||||
|
||||
memset(&tmp, 0xab, sizeof(tmp));
|
||||
|
||||
in = (struct sockaddr_in *)&curr;
|
||||
if (CHECK(memcmp(&curr, &tmp, sizeof(tmp)), "check_kprobe_res",
|
||||
"wrong kprobe res from probe write: %s:%u\n",
|
||||
inet_ntoa(in->sin_addr), ntohs(in->sin_port)))
|
||||
goto cleanup;
|
||||
cleanup:
|
||||
bpf_link__destroy(kprobe_link);
|
||||
bpf_object__close(obj);
|
||||
}
|
||||
@@ -79,11 +79,11 @@ int trace_kfree_skb(struct trace_kfree_skb *ctx)
|
||||
func = ptr->func;
|
||||
}));
|
||||
|
||||
bpf_probe_read(&pkt_type, sizeof(pkt_type), _(&skb->__pkt_type_offset));
|
||||
bpf_probe_read_kernel(&pkt_type, sizeof(pkt_type), _(&skb->__pkt_type_offset));
|
||||
pkt_type &= 7;
|
||||
|
||||
/* read eth proto */
|
||||
bpf_probe_read(&pkt_data, sizeof(pkt_data), data + 12);
|
||||
bpf_probe_read_kernel(&pkt_data, sizeof(pkt_data), data + 12);
|
||||
|
||||
bpf_printk("rcuhead.next %llx func %llx\n", ptr, func);
|
||||
bpf_printk("skb->len %d users %d pkt_type %x\n",
|
||||
|
||||
@@ -72,9 +72,9 @@ static __always_inline void *get_thread_state(void *tls_base, PidData *pidData)
|
||||
void* thread_state;
|
||||
int key;
|
||||
|
||||
bpf_probe_read(&key, sizeof(key), (void*)(long)pidData->tls_key_addr);
|
||||
bpf_probe_read(&thread_state, sizeof(thread_state),
|
||||
tls_base + 0x310 + key * 0x10 + 0x08);
|
||||
bpf_probe_read_user(&key, sizeof(key), (void*)(long)pidData->tls_key_addr);
|
||||
bpf_probe_read_user(&thread_state, sizeof(thread_state),
|
||||
tls_base + 0x310 + key * 0x10 + 0x08);
|
||||
return thread_state;
|
||||
}
|
||||
|
||||
@@ -82,31 +82,33 @@ static __always_inline bool get_frame_data(void *frame_ptr, PidData *pidData,
|
||||
FrameData *frame, Symbol *symbol)
|
||||
{
|
||||
// read data from PyFrameObject
|
||||
bpf_probe_read(&frame->f_back,
|
||||
sizeof(frame->f_back),
|
||||
frame_ptr + pidData->offsets.PyFrameObject_back);
|
||||
bpf_probe_read(&frame->f_code,
|
||||
sizeof(frame->f_code),
|
||||
frame_ptr + pidData->offsets.PyFrameObject_code);
|
||||
bpf_probe_read_user(&frame->f_back,
|
||||
sizeof(frame->f_back),
|
||||
frame_ptr + pidData->offsets.PyFrameObject_back);
|
||||
bpf_probe_read_user(&frame->f_code,
|
||||
sizeof(frame->f_code),
|
||||
frame_ptr + pidData->offsets.PyFrameObject_code);
|
||||
|
||||
// read data from PyCodeObject
|
||||
if (!frame->f_code)
|
||||
return false;
|
||||
bpf_probe_read(&frame->co_filename,
|
||||
sizeof(frame->co_filename),
|
||||
frame->f_code + pidData->offsets.PyCodeObject_filename);
|
||||
bpf_probe_read(&frame->co_name,
|
||||
sizeof(frame->co_name),
|
||||
frame->f_code + pidData->offsets.PyCodeObject_name);
|
||||
bpf_probe_read_user(&frame->co_filename,
|
||||
sizeof(frame->co_filename),
|
||||
frame->f_code + pidData->offsets.PyCodeObject_filename);
|
||||
bpf_probe_read_user(&frame->co_name,
|
||||
sizeof(frame->co_name),
|
||||
frame->f_code + pidData->offsets.PyCodeObject_name);
|
||||
// read actual names into symbol
|
||||
if (frame->co_filename)
|
||||
bpf_probe_read_str(&symbol->file,
|
||||
sizeof(symbol->file),
|
||||
frame->co_filename + pidData->offsets.String_data);
|
||||
bpf_probe_read_user_str(&symbol->file,
|
||||
sizeof(symbol->file),
|
||||
frame->co_filename +
|
||||
pidData->offsets.String_data);
|
||||
if (frame->co_name)
|
||||
bpf_probe_read_str(&symbol->name,
|
||||
sizeof(symbol->name),
|
||||
frame->co_name + pidData->offsets.String_data);
|
||||
bpf_probe_read_user_str(&symbol->name,
|
||||
sizeof(symbol->name),
|
||||
frame->co_name +
|
||||
pidData->offsets.String_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -174,9 +176,9 @@ static __always_inline int __on_event(struct pt_regs *ctx)
|
||||
event->kernel_stack_id = bpf_get_stackid(ctx, &stackmap, 0);
|
||||
|
||||
void* thread_state_current = (void*)0;
|
||||
bpf_probe_read(&thread_state_current,
|
||||
sizeof(thread_state_current),
|
||||
(void*)(long)pidData->current_state_addr);
|
||||
bpf_probe_read_user(&thread_state_current,
|
||||
sizeof(thread_state_current),
|
||||
(void*)(long)pidData->current_state_addr);
|
||||
|
||||
struct task_struct* task = (struct task_struct*)bpf_get_current_task();
|
||||
void* tls_base = (void*)task;
|
||||
@@ -188,11 +190,13 @@ static __always_inline int __on_event(struct pt_regs *ctx)
|
||||
if (pidData->use_tls) {
|
||||
uint64_t pthread_created;
|
||||
uint64_t pthread_self;
|
||||
bpf_probe_read(&pthread_self, sizeof(pthread_self), tls_base + 0x10);
|
||||
bpf_probe_read_user(&pthread_self, sizeof(pthread_self),
|
||||
tls_base + 0x10);
|
||||
|
||||
bpf_probe_read(&pthread_created,
|
||||
sizeof(pthread_created),
|
||||
thread_state + pidData->offsets.PyThreadState_thread);
|
||||
bpf_probe_read_user(&pthread_created,
|
||||
sizeof(pthread_created),
|
||||
thread_state +
|
||||
pidData->offsets.PyThreadState_thread);
|
||||
event->pthread_match = pthread_created == pthread_self;
|
||||
} else {
|
||||
event->pthread_match = 1;
|
||||
@@ -204,9 +208,10 @@ static __always_inline int __on_event(struct pt_regs *ctx)
|
||||
Symbol sym = {};
|
||||
int cur_cpu = bpf_get_smp_processor_id();
|
||||
|
||||
bpf_probe_read(&frame_ptr,
|
||||
sizeof(frame_ptr),
|
||||
thread_state + pidData->offsets.PyThreadState_frame);
|
||||
bpf_probe_read_user(&frame_ptr,
|
||||
sizeof(frame_ptr),
|
||||
thread_state +
|
||||
pidData->offsets.PyThreadState_frame);
|
||||
|
||||
int32_t* symbol_counter = bpf_map_lookup_elem(&symbolmap, &sym);
|
||||
if (symbol_counter == NULL)
|
||||
|
||||
@@ -98,7 +98,7 @@ struct strobe_map_raw {
|
||||
/*
|
||||
* having volatile doesn't change anything on BPF side, but clang
|
||||
* emits warnings for passing `volatile const char *` into
|
||||
* bpf_probe_read_str that expects just `const char *`
|
||||
* bpf_probe_read_user_str that expects just `const char *`
|
||||
*/
|
||||
const char* tag;
|
||||
/*
|
||||
@@ -309,18 +309,18 @@ static __always_inline void *calc_location(struct strobe_value_loc *loc,
|
||||
dtv_t *dtv;
|
||||
void *tls_ptr;
|
||||
|
||||
bpf_probe_read(&tls_index, sizeof(struct tls_index),
|
||||
(void *)loc->offset);
|
||||
bpf_probe_read_user(&tls_index, sizeof(struct tls_index),
|
||||
(void *)loc->offset);
|
||||
/* valid module index is always positive */
|
||||
if (tls_index.module > 0) {
|
||||
/* dtv = ((struct tcbhead *)tls_base)->dtv[tls_index.module] */
|
||||
bpf_probe_read(&dtv, sizeof(dtv),
|
||||
&((struct tcbhead *)tls_base)->dtv);
|
||||
bpf_probe_read_user(&dtv, sizeof(dtv),
|
||||
&((struct tcbhead *)tls_base)->dtv);
|
||||
dtv += tls_index.module;
|
||||
} else {
|
||||
dtv = NULL;
|
||||
}
|
||||
bpf_probe_read(&tls_ptr, sizeof(void *), dtv);
|
||||
bpf_probe_read_user(&tls_ptr, sizeof(void *), dtv);
|
||||
/* if pointer has (void *)-1 value, then TLS wasn't initialized yet */
|
||||
return tls_ptr && tls_ptr != (void *)-1
|
||||
? tls_ptr + tls_index.offset
|
||||
@@ -336,7 +336,7 @@ static __always_inline void read_int_var(struct strobemeta_cfg *cfg,
|
||||
if (!location)
|
||||
return;
|
||||
|
||||
bpf_probe_read(value, sizeof(struct strobe_value_generic), location);
|
||||
bpf_probe_read_user(value, sizeof(struct strobe_value_generic), location);
|
||||
data->int_vals[idx] = value->val;
|
||||
if (value->header.len)
|
||||
data->int_vals_set_mask |= (1 << idx);
|
||||
@@ -356,13 +356,13 @@ static __always_inline uint64_t read_str_var(struct strobemeta_cfg *cfg,
|
||||
if (!location)
|
||||
return 0;
|
||||
|
||||
bpf_probe_read(value, sizeof(struct strobe_value_generic), location);
|
||||
len = bpf_probe_read_str(payload, STROBE_MAX_STR_LEN, value->ptr);
|
||||
bpf_probe_read_user(value, sizeof(struct strobe_value_generic), location);
|
||||
len = bpf_probe_read_user_str(payload, STROBE_MAX_STR_LEN, value->ptr);
|
||||
/*
|
||||
* if bpf_probe_read_str returns error (<0), due to casting to
|
||||
* if bpf_probe_read_user_str returns error (<0), due to casting to
|
||||
* unsinged int, it will become big number, so next check is
|
||||
* sufficient to check for errors AND prove to BPF verifier, that
|
||||
* bpf_probe_read_str won't return anything bigger than
|
||||
* bpf_probe_read_user_str won't return anything bigger than
|
||||
* STROBE_MAX_STR_LEN
|
||||
*/
|
||||
if (len > STROBE_MAX_STR_LEN)
|
||||
@@ -391,8 +391,8 @@ static __always_inline void *read_map_var(struct strobemeta_cfg *cfg,
|
||||
if (!location)
|
||||
return payload;
|
||||
|
||||
bpf_probe_read(value, sizeof(struct strobe_value_generic), location);
|
||||
if (bpf_probe_read(&map, sizeof(struct strobe_map_raw), value->ptr))
|
||||
bpf_probe_read_user(value, sizeof(struct strobe_value_generic), location);
|
||||
if (bpf_probe_read_user(&map, sizeof(struct strobe_map_raw), value->ptr))
|
||||
return payload;
|
||||
|
||||
descr->id = map.id;
|
||||
@@ -402,7 +402,7 @@ static __always_inline void *read_map_var(struct strobemeta_cfg *cfg,
|
||||
data->req_meta_valid = 1;
|
||||
}
|
||||
|
||||
len = bpf_probe_read_str(payload, STROBE_MAX_STR_LEN, map.tag);
|
||||
len = bpf_probe_read_user_str(payload, STROBE_MAX_STR_LEN, map.tag);
|
||||
if (len <= STROBE_MAX_STR_LEN) {
|
||||
descr->tag_len = len;
|
||||
payload += len;
|
||||
@@ -418,15 +418,15 @@ static __always_inline void *read_map_var(struct strobemeta_cfg *cfg,
|
||||
break;
|
||||
|
||||
descr->key_lens[i] = 0;
|
||||
len = bpf_probe_read_str(payload, STROBE_MAX_STR_LEN,
|
||||
map.entries[i].key);
|
||||
len = bpf_probe_read_user_str(payload, STROBE_MAX_STR_LEN,
|
||||
map.entries[i].key);
|
||||
if (len <= STROBE_MAX_STR_LEN) {
|
||||
descr->key_lens[i] = len;
|
||||
payload += len;
|
||||
}
|
||||
descr->val_lens[i] = 0;
|
||||
len = bpf_probe_read_str(payload, STROBE_MAX_STR_LEN,
|
||||
map.entries[i].val);
|
||||
len = bpf_probe_read_user_str(payload, STROBE_MAX_STR_LEN,
|
||||
map.entries[i].val);
|
||||
if (len <= STROBE_MAX_STR_LEN) {
|
||||
descr->val_lens[i] = len;
|
||||
payload += len;
|
||||
|
||||
31
tools/testing/selftests/bpf/progs/test_pinning.c
Normal file
31
tools/testing/selftests/bpf/progs/test_pinning.c
Normal file
@@ -0,0 +1,31 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
int _version SEC("version") = 1;
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__type(key, __u32);
|
||||
__type(value, __u64);
|
||||
__uint(pinning, LIBBPF_PIN_BY_NAME);
|
||||
} pinmap SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, 1);
|
||||
__type(key, __u32);
|
||||
__type(value, __u64);
|
||||
} nopinmap SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__type(key, __u32);
|
||||
__type(value, __u64);
|
||||
__uint(pinning, LIBBPF_PIN_NONE);
|
||||
} nopinmap2 SEC(".maps");
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
16
tools/testing/selftests/bpf/progs/test_pinning_invalid.c
Normal file
16
tools/testing/selftests/bpf/progs/test_pinning_invalid.c
Normal file
@@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
int _version SEC("version") = 1;
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__type(key, __u32);
|
||||
__type(value, __u64);
|
||||
__uint(pinning, 2); /* invalid */
|
||||
} nopinmap3 SEC(".maps");
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
26
tools/testing/selftests/bpf/progs/test_probe_user.c
Normal file
26
tools/testing/selftests/bpf/progs/test_probe_user.c
Normal file
@@ -0,0 +1,26 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/bpf.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "bpf_helpers.h"
|
||||
#include "bpf_tracing.h"
|
||||
|
||||
static struct sockaddr_in old;
|
||||
|
||||
SEC("kprobe/__sys_connect")
|
||||
int handle_sys_connect(struct pt_regs *ctx)
|
||||
{
|
||||
void *ptr = (void *)PT_REGS_PARM2(ctx);
|
||||
struct sockaddr_in new;
|
||||
|
||||
bpf_probe_read_user(&old, sizeof(old), ptr);
|
||||
__builtin_memset(&new, 0xab, sizeof(new));
|
||||
bpf_probe_write_user(ptr, &new, sizeof(new));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
@@ -38,7 +38,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
#define _(P) ({typeof(P) val = 0; bpf_probe_read(&val, sizeof(val), &P); val;})
|
||||
#define _(P) ({typeof(P) val = 0; bpf_probe_read_kernel(&val, sizeof(val), &P); val;})
|
||||
#define TCP_ESTATS_MAGIC 0xBAADBEEF
|
||||
|
||||
/* This test case needs "sock" and "pt_regs" data structure.
|
||||
|
||||
@@ -314,9 +314,6 @@ class DebugfsDir:
|
||||
continue
|
||||
|
||||
p = os.path.join(path, f)
|
||||
if not os.stat(p).st_mode & stat.S_IRUSR:
|
||||
continue
|
||||
|
||||
if os.path.isfile(p) and os.access(p, os.R_OK):
|
||||
_, out = cmd('cat %s/%s' % (path, f))
|
||||
dfs[f] = out.strip()
|
||||
|
||||
@@ -120,6 +120,29 @@ static struct sysctl_test tests[] = {
|
||||
.newval = "(none)", /* same as default, should fail anyway */
|
||||
.result = OP_EPERM,
|
||||
},
|
||||
{
|
||||
.descr = "ctx:write sysctl:write read ok narrow",
|
||||
.insns = {
|
||||
/* u64 w = (u16)write & 1; */
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
BPF_LDX_MEM(BPF_H, BPF_REG_7, BPF_REG_1,
|
||||
offsetof(struct bpf_sysctl, write)),
|
||||
#else
|
||||
BPF_LDX_MEM(BPF_H, BPF_REG_7, BPF_REG_1,
|
||||
offsetof(struct bpf_sysctl, write) + 2),
|
||||
#endif
|
||||
BPF_ALU64_IMM(BPF_AND, BPF_REG_7, 1),
|
||||
/* return 1 - w; */
|
||||
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||
BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_7),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.attach_type = BPF_CGROUP_SYSCTL,
|
||||
.sysctl = "kernel/domainname",
|
||||
.open_flags = O_WRONLY,
|
||||
.newval = "(none)", /* same as default, should fail anyway */
|
||||
.result = OP_EPERM,
|
||||
},
|
||||
{
|
||||
.descr = "ctx:write sysctl:read write reject",
|
||||
.insns = {
|
||||
|
||||
Reference in New Issue
Block a user