Commit 29684d80 authored by David S. Miller's avatar David S. Miller

Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf

Alexei Starovoitov says:

====================
pull-request: bpf 2021-04-01

The following pull-request contains BPF updates for your *net* tree.

We've added 11 non-merge commits during the last 8 day(s) which contain
a total of 10 files changed, 151 insertions(+), 26 deletions(-).

The main changes are:

1) xsk creation fixes, from Ciara.

2) bpf_get_task_stack fix, from Dave.

3) trampoline in modules fix, from Jiri.

4) bpf_obj_get fix for links and progs, from Lorenz.

5) struct_ops progs must be gpl compatible fix, from Toke.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9256ce33 6dcc4e38
...@@ -40,6 +40,7 @@ struct bpf_local_storage; ...@@ -40,6 +40,7 @@ struct bpf_local_storage;
struct bpf_local_storage_map; struct bpf_local_storage_map;
struct kobject; struct kobject;
struct mem_cgroup; struct mem_cgroup;
struct module;
extern struct idr btf_idr; extern struct idr btf_idr;
extern spinlock_t btf_idr_lock; extern spinlock_t btf_idr_lock;
...@@ -623,6 +624,7 @@ struct bpf_trampoline { ...@@ -623,6 +624,7 @@ struct bpf_trampoline {
/* Executable image of trampoline */ /* Executable image of trampoline */
struct bpf_tramp_image *cur_image; struct bpf_tramp_image *cur_image;
u64 selector; u64 selector;
struct module *mod;
}; };
struct bpf_attach_target_info { struct bpf_attach_target_info {
......
...@@ -84,7 +84,7 @@ static const char *const bpf_atomic_alu_string[16] = { ...@@ -84,7 +84,7 @@ static const char *const bpf_atomic_alu_string[16] = {
[BPF_ADD >> 4] = "add", [BPF_ADD >> 4] = "add",
[BPF_AND >> 4] = "and", [BPF_AND >> 4] = "and",
[BPF_OR >> 4] = "or", [BPF_OR >> 4] = "or",
[BPF_XOR >> 4] = "or", [BPF_XOR >> 4] = "xor",
}; };
static const char *const bpf_ldst_string[] = { static const char *const bpf_ldst_string[] = {
......
...@@ -543,11 +543,11 @@ int bpf_obj_get_user(const char __user *pathname, int flags) ...@@ -543,11 +543,11 @@ int bpf_obj_get_user(const char __user *pathname, int flags)
return PTR_ERR(raw); return PTR_ERR(raw);
if (type == BPF_TYPE_PROG) if (type == BPF_TYPE_PROG)
ret = bpf_prog_new_fd(raw); ret = (f_flags != O_RDWR) ? -EINVAL : bpf_prog_new_fd(raw);
else if (type == BPF_TYPE_MAP) else if (type == BPF_TYPE_MAP)
ret = bpf_map_new_fd(raw, f_flags); ret = bpf_map_new_fd(raw, f_flags);
else if (type == BPF_TYPE_LINK) else if (type == BPF_TYPE_LINK)
ret = bpf_link_new_fd(raw); ret = (f_flags != O_RDWR) ? -EINVAL : bpf_link_new_fd(raw);
else else
return -ENOENT; return -ENOENT;
......
...@@ -517,9 +517,17 @@ const struct bpf_func_proto bpf_get_stack_proto = { ...@@ -517,9 +517,17 @@ const struct bpf_func_proto bpf_get_stack_proto = {
BPF_CALL_4(bpf_get_task_stack, struct task_struct *, task, void *, buf, BPF_CALL_4(bpf_get_task_stack, struct task_struct *, task, void *, buf,
u32, size, u64, flags) u32, size, u64, flags)
{ {
struct pt_regs *regs = task_pt_regs(task); struct pt_regs *regs;
long res;
return __bpf_get_stack(regs, task, NULL, buf, size, flags); if (!try_get_task_stack(task))
return -EFAULT;
regs = task_pt_regs(task);
res = __bpf_get_stack(regs, task, NULL, buf, size, flags);
put_task_stack(task);
return res;
} }
BTF_ID_LIST_SINGLE(bpf_get_task_stack_btf_ids, struct, task_struct) BTF_ID_LIST_SINGLE(bpf_get_task_stack_btf_ids, struct, task_struct)
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/btf.h> #include <linux/btf.h>
#include <linux/rcupdate_trace.h> #include <linux/rcupdate_trace.h>
#include <linux/rcupdate_wait.h> #include <linux/rcupdate_wait.h>
#include <linux/module.h>
/* dummy _ops. The verifier will operate on target program's ops. */ /* dummy _ops. The verifier will operate on target program's ops. */
const struct bpf_verifier_ops bpf_extension_verifier_ops = { const struct bpf_verifier_ops bpf_extension_verifier_ops = {
...@@ -87,6 +88,26 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key) ...@@ -87,6 +88,26 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
return tr; return tr;
} }
static int bpf_trampoline_module_get(struct bpf_trampoline *tr)
{
struct module *mod;
int err = 0;
preempt_disable();
mod = __module_text_address((unsigned long) tr->func.addr);
if (mod && !try_module_get(mod))
err = -ENOENT;
preempt_enable();
tr->mod = mod;
return err;
}
static void bpf_trampoline_module_put(struct bpf_trampoline *tr)
{
module_put(tr->mod);
tr->mod = NULL;
}
static int is_ftrace_location(void *ip) static int is_ftrace_location(void *ip)
{ {
long addr; long addr;
...@@ -108,6 +129,9 @@ static int unregister_fentry(struct bpf_trampoline *tr, void *old_addr) ...@@ -108,6 +129,9 @@ static int unregister_fentry(struct bpf_trampoline *tr, void *old_addr)
ret = unregister_ftrace_direct((long)ip, (long)old_addr); ret = unregister_ftrace_direct((long)ip, (long)old_addr);
else else
ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, old_addr, NULL); ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, old_addr, NULL);
if (!ret)
bpf_trampoline_module_put(tr);
return ret; return ret;
} }
...@@ -134,10 +158,16 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr) ...@@ -134,10 +158,16 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
return ret; return ret;
tr->func.ftrace_managed = ret; tr->func.ftrace_managed = ret;
if (bpf_trampoline_module_get(tr))
return -ENOENT;
if (tr->func.ftrace_managed) if (tr->func.ftrace_managed)
ret = register_ftrace_direct((long)ip, (long)new_addr); ret = register_ftrace_direct((long)ip, (long)new_addr);
else else
ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, NULL, new_addr); ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, NULL, new_addr);
if (ret)
bpf_trampoline_module_put(tr);
return ret; return ret;
} }
......
...@@ -12158,6 +12158,11 @@ static int check_struct_ops_btf_id(struct bpf_verifier_env *env) ...@@ -12158,6 +12158,11 @@ static int check_struct_ops_btf_id(struct bpf_verifier_env *env)
u32 btf_id, member_idx; u32 btf_id, member_idx;
const char *mname; const char *mname;
if (!prog->gpl_compatible) {
verbose(env, "struct ops programs must have a GPL compatible license\n");
return -EINVAL;
}
btf_id = prog->aux->attach_btf_id; btf_id = prog->aux->attach_btf_id;
st_ops = bpf_struct_ops_find(btf_id); st_ops = bpf_struct_ops_find(btf_id);
if (!st_ops) { if (!st_ops) {
......
...@@ -227,7 +227,7 @@ static int ringbuf_process_ring(struct ring* r) ...@@ -227,7 +227,7 @@ static int ringbuf_process_ring(struct ring* r)
if ((len & BPF_RINGBUF_DISCARD_BIT) == 0) { if ((len & BPF_RINGBUF_DISCARD_BIT) == 0) {
sample = (void *)len_ptr + BPF_RINGBUF_HDR_SZ; sample = (void *)len_ptr + BPF_RINGBUF_HDR_SZ;
err = r->sample_cb(r->ctx, sample, len); err = r->sample_cb(r->ctx, sample, len);
if (err) { if (err < 0) {
/* update consumer pos and bail out */ /* update consumer pos and bail out */
smp_store_release(r->consumer_pos, smp_store_release(r->consumer_pos,
cons_pos); cons_pos);
......
...@@ -59,6 +59,8 @@ struct xsk_umem { ...@@ -59,6 +59,8 @@ struct xsk_umem {
int fd; int fd;
int refcount; int refcount;
struct list_head ctx_list; struct list_head ctx_list;
bool rx_ring_setup_done;
bool tx_ring_setup_done;
}; };
struct xsk_ctx { struct xsk_ctx {
...@@ -743,26 +745,30 @@ static struct xsk_ctx *xsk_get_ctx(struct xsk_umem *umem, int ifindex, ...@@ -743,26 +745,30 @@ static struct xsk_ctx *xsk_get_ctx(struct xsk_umem *umem, int ifindex,
return NULL; return NULL;
} }
static void xsk_put_ctx(struct xsk_ctx *ctx) static void xsk_put_ctx(struct xsk_ctx *ctx, bool unmap)
{ {
struct xsk_umem *umem = ctx->umem; struct xsk_umem *umem = ctx->umem;
struct xdp_mmap_offsets off; struct xdp_mmap_offsets off;
int err; int err;
if (--ctx->refcount == 0) { if (--ctx->refcount)
return;
if (!unmap)
goto out_free;
err = xsk_get_mmap_offsets(umem->fd, &off); err = xsk_get_mmap_offsets(umem->fd, &off);
if (!err) { if (err)
munmap(ctx->fill->ring - off.fr.desc, goto out_free;
off.fr.desc + umem->config.fill_size *
munmap(ctx->fill->ring - off.fr.desc, off.fr.desc + umem->config.fill_size *
sizeof(__u64)); sizeof(__u64));
munmap(ctx->comp->ring - off.cr.desc, munmap(ctx->comp->ring - off.cr.desc, off.cr.desc + umem->config.comp_size *
off.cr.desc + umem->config.comp_size *
sizeof(__u64)); sizeof(__u64));
}
out_free:
list_del(&ctx->list); list_del(&ctx->list);
free(ctx); free(ctx);
}
} }
static struct xsk_ctx *xsk_create_ctx(struct xsk_socket *xsk, static struct xsk_ctx *xsk_create_ctx(struct xsk_socket *xsk,
...@@ -797,8 +803,6 @@ static struct xsk_ctx *xsk_create_ctx(struct xsk_socket *xsk, ...@@ -797,8 +803,6 @@ static struct xsk_ctx *xsk_create_ctx(struct xsk_socket *xsk,
memcpy(ctx->ifname, ifname, IFNAMSIZ - 1); memcpy(ctx->ifname, ifname, IFNAMSIZ - 1);
ctx->ifname[IFNAMSIZ - 1] = '\0'; ctx->ifname[IFNAMSIZ - 1] = '\0';
umem->fill_save = NULL;
umem->comp_save = NULL;
ctx->fill = fill; ctx->fill = fill;
ctx->comp = comp; ctx->comp = comp;
list_add(&ctx->list, &umem->ctx_list); list_add(&ctx->list, &umem->ctx_list);
...@@ -854,6 +858,8 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr, ...@@ -854,6 +858,8 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
struct xsk_socket *xsk; struct xsk_socket *xsk;
struct xsk_ctx *ctx; struct xsk_ctx *ctx;
int err, ifindex; int err, ifindex;
bool unmap = umem->fill_save != fill;
bool rx_setup_done = false, tx_setup_done = false;
if (!umem || !xsk_ptr || !(rx || tx)) if (!umem || !xsk_ptr || !(rx || tx))
return -EFAULT; return -EFAULT;
...@@ -881,6 +887,8 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr, ...@@ -881,6 +887,8 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
} }
} else { } else {
xsk->fd = umem->fd; xsk->fd = umem->fd;
rx_setup_done = umem->rx_ring_setup_done;
tx_setup_done = umem->tx_ring_setup_done;
} }
ctx = xsk_get_ctx(umem, ifindex, queue_id); ctx = xsk_get_ctx(umem, ifindex, queue_id);
...@@ -899,7 +907,7 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr, ...@@ -899,7 +907,7 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
} }
xsk->ctx = ctx; xsk->ctx = ctx;
if (rx) { if (rx && !rx_setup_done) {
err = setsockopt(xsk->fd, SOL_XDP, XDP_RX_RING, err = setsockopt(xsk->fd, SOL_XDP, XDP_RX_RING,
&xsk->config.rx_size, &xsk->config.rx_size,
sizeof(xsk->config.rx_size)); sizeof(xsk->config.rx_size));
...@@ -907,8 +915,10 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr, ...@@ -907,8 +915,10 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
err = -errno; err = -errno;
goto out_put_ctx; goto out_put_ctx;
} }
if (xsk->fd == umem->fd)
umem->rx_ring_setup_done = true;
} }
if (tx) { if (tx && !tx_setup_done) {
err = setsockopt(xsk->fd, SOL_XDP, XDP_TX_RING, err = setsockopt(xsk->fd, SOL_XDP, XDP_TX_RING,
&xsk->config.tx_size, &xsk->config.tx_size,
sizeof(xsk->config.tx_size)); sizeof(xsk->config.tx_size));
...@@ -916,6 +926,8 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr, ...@@ -916,6 +926,8 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
err = -errno; err = -errno;
goto out_put_ctx; goto out_put_ctx;
} }
if (xsk->fd == umem->fd)
umem->rx_ring_setup_done = true;
} }
err = xsk_get_mmap_offsets(xsk->fd, &off); err = xsk_get_mmap_offsets(xsk->fd, &off);
...@@ -994,6 +1006,8 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr, ...@@ -994,6 +1006,8 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
} }
*xsk_ptr = xsk; *xsk_ptr = xsk;
umem->fill_save = NULL;
umem->comp_save = NULL;
return 0; return 0;
out_mmap_tx: out_mmap_tx:
...@@ -1005,7 +1019,7 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr, ...@@ -1005,7 +1019,7 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
munmap(rx_map, off.rx.desc + munmap(rx_map, off.rx.desc +
xsk->config.rx_size * sizeof(struct xdp_desc)); xsk->config.rx_size * sizeof(struct xdp_desc));
out_put_ctx: out_put_ctx:
xsk_put_ctx(ctx); xsk_put_ctx(ctx, unmap);
out_socket: out_socket:
if (--umem->refcount) if (--umem->refcount)
close(xsk->fd); close(xsk->fd);
...@@ -1019,6 +1033,9 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname, ...@@ -1019,6 +1033,9 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
struct xsk_ring_cons *rx, struct xsk_ring_prod *tx, struct xsk_ring_cons *rx, struct xsk_ring_prod *tx,
const struct xsk_socket_config *usr_config) const struct xsk_socket_config *usr_config)
{ {
if (!umem)
return -EFAULT;
return xsk_socket__create_shared(xsk_ptr, ifname, queue_id, umem, return xsk_socket__create_shared(xsk_ptr, ifname, queue_id, umem,
rx, tx, umem->fill_save, rx, tx, umem->fill_save,
umem->comp_save, usr_config); umem->comp_save, usr_config);
...@@ -1068,7 +1085,7 @@ void xsk_socket__delete(struct xsk_socket *xsk) ...@@ -1068,7 +1085,7 @@ void xsk_socket__delete(struct xsk_socket *xsk)
} }
} }
xsk_put_ctx(ctx); xsk_put_ctx(ctx, true);
umem->refcount--; umem->refcount--;
/* Do not close an fd that also has an associated umem connected /* Do not close an fd that also has an associated umem connected
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <test_progs.h> #include <test_progs.h>
#include "bpf_dctcp.skel.h" #include "bpf_dctcp.skel.h"
#include "bpf_cubic.skel.h" #include "bpf_cubic.skel.h"
#include "bpf_tcp_nogpl.skel.h"
#define min(a, b) ((a) < (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b))
...@@ -227,10 +228,53 @@ static void test_dctcp(void) ...@@ -227,10 +228,53 @@ static void test_dctcp(void)
bpf_dctcp__destroy(dctcp_skel); bpf_dctcp__destroy(dctcp_skel);
} }
static char *err_str;
static bool found;
static int libbpf_debug_print(enum libbpf_print_level level,
const char *format, va_list args)
{
char *log_buf;
if (level != LIBBPF_WARN ||
strcmp(format, "libbpf: \n%s\n")) {
vprintf(format, args);
return 0;
}
log_buf = va_arg(args, char *);
if (!log_buf)
goto out;
if (err_str && strstr(log_buf, err_str) != NULL)
found = true;
out:
printf(format, log_buf);
return 0;
}
static void test_invalid_license(void)
{
libbpf_print_fn_t old_print_fn;
struct bpf_tcp_nogpl *skel;
err_str = "struct ops programs must have a GPL compatible license";
found = false;
old_print_fn = libbpf_set_print(libbpf_debug_print);
skel = bpf_tcp_nogpl__open_and_load();
ASSERT_NULL(skel, "bpf_tcp_nogpl");
ASSERT_EQ(found, true, "expected_err_msg");
bpf_tcp_nogpl__destroy(skel);
libbpf_set_print(old_print_fn);
}
void test_bpf_tcp_ca(void) void test_bpf_tcp_ca(void)
{ {
if (test__start_subtest("dctcp")) if (test__start_subtest("dctcp"))
test_dctcp(); test_dctcp();
if (test__start_subtest("cubic")) if (test__start_subtest("cubic"))
test_cubic(); test_cubic();
if (test__start_subtest("invalid_license"))
test_invalid_license();
} }
// SPDX-License-Identifier: GPL-2.0
#include <linux/bpf.h>
#include <linux/types.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include "bpf_tcp_helpers.h"
char _license[] SEC("license") = "X";
void BPF_STRUCT_OPS(nogpltcp_init, struct sock *sk)
{
}
SEC(".struct_ops")
struct tcp_congestion_ops bpf_nogpltcp = {
.init = (void *)nogpltcp_init,
.name = "bpf_nogpltcp",
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment