Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
Alexei Starovoitov says: ==================== pull-request: bpf-next 2020-07-13 The following pull-request contains BPF updates for your *net-next* tree. We've added 36 non-merge commits during the last 7 day(s) which contain a total of 62 files changed, 2242 insertions(+), 468 deletions(-). The main changes are: 1) Avoid trace_printk warning banner by switching bpf_trace_printk to use its own tracing event, from Alan. 2) Better libbpf support on older kernels, from Andrii. 3) Additional AF_XDP stats, from Ciara. 4) build time resolution of BTF IDs, from Jiri. 5) BPF_CGROUP_INET_SOCK_RELEASE hook, from Stanislav. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
103
kernel/bpf/btf.c
103
kernel/bpf/btf.c
@@ -18,6 +18,7 @@
|
||||
#include <linux/sort.h>
|
||||
#include <linux/bpf_verifier.h>
|
||||
#include <linux/btf.h>
|
||||
#include <linux/btf_ids.h>
|
||||
#include <linux/skmsg.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <net/sock.h>
|
||||
@@ -3621,12 +3622,15 @@ static int btf_translate_to_vmlinux(struct bpf_verifier_log *log,
|
||||
return kern_ctx_type->type;
|
||||
}
|
||||
|
||||
BTF_ID_LIST(bpf_ctx_convert_btf_id)
|
||||
BTF_ID(struct, bpf_ctx_convert)
|
||||
|
||||
struct btf *btf_parse_vmlinux(void)
|
||||
{
|
||||
struct btf_verifier_env *env = NULL;
|
||||
struct bpf_verifier_log *log;
|
||||
struct btf *btf = NULL;
|
||||
int err, btf_id;
|
||||
int err;
|
||||
|
||||
env = kzalloc(sizeof(*env), GFP_KERNEL | __GFP_NOWARN);
|
||||
if (!env)
|
||||
@@ -3659,14 +3663,8 @@ struct btf *btf_parse_vmlinux(void)
|
||||
if (err)
|
||||
goto errout;
|
||||
|
||||
/* find struct bpf_ctx_convert for type checking later */
|
||||
btf_id = btf_find_by_name_kind(btf, "bpf_ctx_convert", BTF_KIND_STRUCT);
|
||||
if (btf_id < 0) {
|
||||
err = btf_id;
|
||||
goto errout;
|
||||
}
|
||||
/* btf_parse_vmlinux() runs under bpf_verifier_lock */
|
||||
bpf_ctx_convert.t = btf_type_by_id(btf, btf_id);
|
||||
bpf_ctx_convert.t = btf_type_by_id(btf, bpf_ctx_convert_btf_id[0]);
|
||||
|
||||
/* find bpf map structs for map_ptr access checking */
|
||||
err = btf_vmlinux_map_ids_init(btf, log);
|
||||
@@ -4079,96 +4077,17 @@ error:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int __btf_resolve_helper_id(struct bpf_verifier_log *log, void *fn,
|
||||
int arg)
|
||||
{
|
||||
char fnname[KSYM_SYMBOL_LEN + 4] = "btf_";
|
||||
const struct btf_param *args;
|
||||
const struct btf_type *t;
|
||||
const char *tname, *sym;
|
||||
u32 btf_id, i;
|
||||
|
||||
if (IS_ERR(btf_vmlinux)) {
|
||||
bpf_log(log, "btf_vmlinux is malformed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sym = kallsyms_lookup((long)fn, NULL, NULL, NULL, fnname + 4);
|
||||
if (!sym) {
|
||||
bpf_log(log, "kernel doesn't have kallsyms\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
for (i = 1; i <= btf_vmlinux->nr_types; i++) {
|
||||
t = btf_type_by_id(btf_vmlinux, i);
|
||||
if (BTF_INFO_KIND(t->info) != BTF_KIND_TYPEDEF)
|
||||
continue;
|
||||
tname = __btf_name_by_offset(btf_vmlinux, t->name_off);
|
||||
if (!strcmp(tname, fnname))
|
||||
break;
|
||||
}
|
||||
if (i > btf_vmlinux->nr_types) {
|
||||
bpf_log(log, "helper %s type is not found\n", fnname);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
t = btf_type_by_id(btf_vmlinux, t->type);
|
||||
if (!btf_type_is_ptr(t))
|
||||
return -EFAULT;
|
||||
t = btf_type_by_id(btf_vmlinux, t->type);
|
||||
if (!btf_type_is_func_proto(t))
|
||||
return -EFAULT;
|
||||
|
||||
args = (const struct btf_param *)(t + 1);
|
||||
if (arg >= btf_type_vlen(t)) {
|
||||
bpf_log(log, "bpf helper %s doesn't have %d-th argument\n",
|
||||
fnname, arg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
t = btf_type_by_id(btf_vmlinux, args[arg].type);
|
||||
if (!btf_type_is_ptr(t) || !t->type) {
|
||||
/* anything but the pointer to struct is a helper config bug */
|
||||
bpf_log(log, "ARG_PTR_TO_BTF is misconfigured\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
btf_id = t->type;
|
||||
t = btf_type_by_id(btf_vmlinux, t->type);
|
||||
/* skip modifiers */
|
||||
while (btf_type_is_modifier(t)) {
|
||||
btf_id = t->type;
|
||||
t = btf_type_by_id(btf_vmlinux, t->type);
|
||||
}
|
||||
if (!btf_type_is_struct(t)) {
|
||||
bpf_log(log, "ARG_PTR_TO_BTF is not a struct\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
bpf_log(log, "helper %s arg%d has btf_id %d struct %s\n", fnname + 4,
|
||||
arg, btf_id, __btf_name_by_offset(btf_vmlinux, t->name_off));
|
||||
return btf_id;
|
||||
}
|
||||
|
||||
int btf_resolve_helper_id(struct bpf_verifier_log *log,
|
||||
const struct bpf_func_proto *fn, int arg)
|
||||
{
|
||||
int *btf_id = &fn->btf_id[arg];
|
||||
int ret;
|
||||
int id;
|
||||
|
||||
if (fn->arg_type[arg] != ARG_PTR_TO_BTF_ID)
|
||||
return -EINVAL;
|
||||
|
||||
ret = READ_ONCE(*btf_id);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* ok to race the search. The result is the same */
|
||||
ret = __btf_resolve_helper_id(log, fn->func, arg);
|
||||
if (!ret) {
|
||||
/* Function argument cannot be type 'void' */
|
||||
bpf_log(log, "BTF resolution bug\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
WRITE_ONCE(*btf_id, ret);
|
||||
return ret;
|
||||
id = fn->btf_id[arg];
|
||||
if (!id || id > btf_vmlinux->nr_types)
|
||||
return -EINVAL;
|
||||
return id;
|
||||
}
|
||||
|
||||
static int __get_type_size(struct btf *btf, u32 btf_id,
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#include <linux/elf.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/irq_work.h>
|
||||
#include <linux/btf_ids.h>
|
||||
#include "percpu_freelist.h"
|
||||
|
||||
#define STACK_CREATE_FLAG_MASK \
|
||||
@@ -576,7 +577,9 @@ BPF_CALL_4(bpf_get_task_stack, struct task_struct *, task, void *, buf,
|
||||
return __bpf_get_stack(regs, task, buf, size, flags);
|
||||
}
|
||||
|
||||
static int bpf_get_task_stack_btf_ids[5];
|
||||
BTF_ID_LIST(bpf_get_task_stack_btf_ids)
|
||||
BTF_ID(struct, task_struct)
|
||||
|
||||
const struct bpf_func_proto bpf_get_task_stack_proto = {
|
||||
.func = bpf_get_task_stack,
|
||||
.gpl_only = false,
|
||||
|
@@ -1981,6 +1981,7 @@ bpf_prog_load_check_attach(enum bpf_prog_type prog_type,
|
||||
case BPF_PROG_TYPE_CGROUP_SOCK:
|
||||
switch (expected_attach_type) {
|
||||
case BPF_CGROUP_INET_SOCK_CREATE:
|
||||
case BPF_CGROUP_INET_SOCK_RELEASE:
|
||||
case BPF_CGROUP_INET4_POST_BIND:
|
||||
case BPF_CGROUP_INET6_POST_BIND:
|
||||
return 0;
|
||||
@@ -2779,6 +2780,7 @@ attach_type_to_prog_type(enum bpf_attach_type attach_type)
|
||||
return BPF_PROG_TYPE_CGROUP_SKB;
|
||||
break;
|
||||
case BPF_CGROUP_INET_SOCK_CREATE:
|
||||
case BPF_CGROUP_INET_SOCK_RELEASE:
|
||||
case BPF_CGROUP_INET4_POST_BIND:
|
||||
case BPF_CGROUP_INET6_POST_BIND:
|
||||
return BPF_PROG_TYPE_CGROUP_SOCK;
|
||||
@@ -2927,6 +2929,7 @@ static int bpf_prog_query(const union bpf_attr *attr,
|
||||
case BPF_CGROUP_INET_INGRESS:
|
||||
case BPF_CGROUP_INET_EGRESS:
|
||||
case BPF_CGROUP_INET_SOCK_CREATE:
|
||||
case BPF_CGROUP_INET_SOCK_RELEASE:
|
||||
case BPF_CGROUP_INET4_BIND:
|
||||
case BPF_CGROUP_INET6_BIND:
|
||||
case BPF_CGROUP_INET4_POST_BIND:
|
||||
|
@@ -31,6 +31,8 @@ ifdef CONFIG_GCOV_PROFILE_FTRACE
|
||||
GCOV_PROFILE := y
|
||||
endif
|
||||
|
||||
CFLAGS_bpf_trace.o := -I$(src)
|
||||
|
||||
CFLAGS_trace_benchmark.o := -I$(src)
|
||||
CFLAGS_trace_events_filter.o := -I$(src)
|
||||
|
||||
|
@@ -11,14 +11,19 @@
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/error-injection.h>
|
||||
#include <linux/btf_ids.h>
|
||||
|
||||
#include <asm/tlb.h>
|
||||
|
||||
#include "trace_probe.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "bpf_trace.h"
|
||||
|
||||
#define bpf_event_rcu_dereference(p) \
|
||||
rcu_dereference_protected(p, lockdep_is_held(&bpf_event_mutex))
|
||||
|
||||
@@ -374,6 +379,30 @@ static void bpf_trace_copy_string(char *buf, void *unsafe_ptr, char fmt_ptype,
|
||||
}
|
||||
}
|
||||
|
||||
static DEFINE_RAW_SPINLOCK(trace_printk_lock);
|
||||
|
||||
#define BPF_TRACE_PRINTK_SIZE 1024
|
||||
|
||||
static inline __printf(1, 0) int bpf_do_trace_printk(const char *fmt, ...)
|
||||
{
|
||||
static char buf[BPF_TRACE_PRINTK_SIZE];
|
||||
unsigned long flags;
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
raw_spin_lock_irqsave(&trace_printk_lock, flags);
|
||||
va_start(ap, fmt);
|
||||
ret = vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
/* vsnprintf() will not append null for zero-length strings */
|
||||
if (ret == 0)
|
||||
buf[0] = '\0';
|
||||
trace_bpf_trace_printk(buf);
|
||||
raw_spin_unlock_irqrestore(&trace_printk_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only limited trace_printk() conversion specifiers allowed:
|
||||
* %d %i %u %x %ld %li %lu %lx %lld %lli %llu %llx %p %pB %pks %pus %s
|
||||
@@ -483,8 +512,7 @@ fmt_next:
|
||||
*/
|
||||
#define __BPF_TP_EMIT() __BPF_ARG3_TP()
|
||||
#define __BPF_TP(...) \
|
||||
__trace_printk(0 /* Fake ip */, \
|
||||
fmt, ##__VA_ARGS__)
|
||||
bpf_do_trace_printk(fmt, ##__VA_ARGS__)
|
||||
|
||||
#define __BPF_ARG1_TP(...) \
|
||||
((mod[0] == 2 || (mod[0] == 1 && __BITS_PER_LONG == 64)) \
|
||||
@@ -521,10 +549,15 @@ static const struct bpf_func_proto bpf_trace_printk_proto = {
|
||||
const struct bpf_func_proto *bpf_get_trace_printk_proto(void)
|
||||
{
|
||||
/*
|
||||
* this program might be calling bpf_trace_printk,
|
||||
* so allocate per-cpu printk buffers
|
||||
* This program might be calling bpf_trace_printk,
|
||||
* so enable the associated bpf_trace/bpf_trace_printk event.
|
||||
* Repeat this each time as it is possible a user has
|
||||
* disabled bpf_trace_printk events. By loading a program
|
||||
* calling bpf_trace_printk() however the user has expressed
|
||||
* the intent to see such events.
|
||||
*/
|
||||
trace_printk_init_buffers();
|
||||
if (trace_set_clr_event("bpf_trace", "bpf_trace_printk", 1))
|
||||
pr_warn_ratelimited("could not enable bpf_trace_printk events");
|
||||
|
||||
return &bpf_trace_printk_proto;
|
||||
}
|
||||
@@ -710,7 +743,9 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int bpf_seq_printf_btf_ids[5];
|
||||
BTF_ID_LIST(bpf_seq_printf_btf_ids)
|
||||
BTF_ID(struct, seq_file)
|
||||
|
||||
static const struct bpf_func_proto bpf_seq_printf_proto = {
|
||||
.func = bpf_seq_printf,
|
||||
.gpl_only = true,
|
||||
@@ -728,7 +763,9 @@ BPF_CALL_3(bpf_seq_write, struct seq_file *, m, const void *, data, u32, len)
|
||||
return seq_write(m, data, len) ? -EOVERFLOW : 0;
|
||||
}
|
||||
|
||||
static int bpf_seq_write_btf_ids[5];
|
||||
BTF_ID_LIST(bpf_seq_write_btf_ids)
|
||||
BTF_ID(struct, seq_file)
|
||||
|
||||
static const struct bpf_func_proto bpf_seq_write_proto = {
|
||||
.func = bpf_seq_write,
|
||||
.gpl_only = true,
|
||||
|
34
kernel/trace/bpf_trace.h
Normal file
34
kernel/trace/bpf_trace.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM bpf_trace
|
||||
|
||||
#if !defined(_TRACE_BPF_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
|
||||
#define _TRACE_BPF_TRACE_H
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
TRACE_EVENT(bpf_trace_printk,
|
||||
|
||||
TP_PROTO(const char *bpf_string),
|
||||
|
||||
TP_ARGS(bpf_string),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(bpf_string, bpf_string)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(bpf_string, bpf_string);
|
||||
),
|
||||
|
||||
TP_printk("%s", __get_str(bpf_string))
|
||||
);
|
||||
|
||||
#endif /* _TRACE_BPF_TRACE_H */
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
#define TRACE_INCLUDE_PATH .
|
||||
#define TRACE_INCLUDE_FILE bpf_trace
|
||||
|
||||
#include <trace/define_trace.h>
|
Reference in New Issue
Block a user