Commit 1612cc4b 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:

====================

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

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

The main changes are:

1) Adjust bpf_mem_alloc buckets to match ksize(), from Hou Tao.

2) Check whether override is allowed in kprobe mult, from Jiri Olsa.

3) Fix btf_id symbol generation with ld.lld, from Jiri and Nick.

4) Fix potential deadlock when using queue and stack maps from NMI, from Toke Høiland-Jørgensen.

Please consider pulling these changes from:

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

Thanks a lot!

Also thanks to reporters, reviewers and testers of commits in this pull-request:

Alan Maguire, Biju Das, Björn Töpel, Dan Carpenter, Daniel Borkmann,
Eduard Zingerman, Hsin-Wei Hung, Marcus Seyfarth, Nathan Chancellor,
Satya Durga Srinivasu Prabhala, Song Liu, Stephen Rothwell
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 615efed8 c0bb9fb0
...@@ -49,7 +49,7 @@ word \ ...@@ -49,7 +49,7 @@ word \
____BTF_ID(symbol, word) ____BTF_ID(symbol, word)
#define __ID(prefix) \ #define __ID(prefix) \
__PASTE(prefix, __COUNTER__) __PASTE(__PASTE(prefix, __COUNTER__), __LINE__)
/* /*
* The BTF_ID defines unique symbol for each ID pointing * The BTF_ID defines unique symbol for each ID pointing
......
...@@ -1962,7 +1962,9 @@ union bpf_attr { ...@@ -1962,7 +1962,9 @@ union bpf_attr {
* performed again, if the helper is used in combination with * performed again, if the helper is used in combination with
* direct packet access. * direct packet access.
* Return * Return
* 0 on success, or a negative error in case of failure. * 0 on success, or a negative error in case of failure. Positive
* error indicates a potential drop or congestion in the target
* device. The particular positive error codes are not defined.
* *
* u64 bpf_get_current_pid_tgid(void) * u64 bpf_get_current_pid_tgid(void)
* Description * Description
......
...@@ -8501,7 +8501,7 @@ bool btf_nested_type_is_trusted(struct bpf_verifier_log *log, ...@@ -8501,7 +8501,7 @@ bool btf_nested_type_is_trusted(struct bpf_verifier_log *log,
tname = btf_name_by_offset(btf, walk_type->name_off); tname = btf_name_by_offset(btf, walk_type->name_off);
ret = snprintf(safe_tname, sizeof(safe_tname), "%s%s", tname, suffix); ret = snprintf(safe_tname, sizeof(safe_tname), "%s%s", tname, suffix);
if (ret < 0) if (ret >= sizeof(safe_tname))
return false; return false;
safe_id = btf_find_by_name_kind(btf, safe_tname, BTF_INFO_KIND(walk_type->info)); safe_id = btf_find_by_name_kind(btf, safe_tname, BTF_INFO_KIND(walk_type->info));
......
...@@ -785,7 +785,8 @@ static void replace_effective_prog(struct cgroup *cgrp, ...@@ -785,7 +785,8 @@ static void replace_effective_prog(struct cgroup *cgrp,
* to descendants * to descendants
* @cgrp: The cgroup which descendants to traverse * @cgrp: The cgroup which descendants to traverse
* @link: A link for which to replace BPF program * @link: A link for which to replace BPF program
* @type: Type of attach operation * @new_prog: &struct bpf_prog for the target BPF program with its refcnt
* incremented
* *
* Must be called with cgroup_mutex held. * Must be called with cgroup_mutex held.
*/ */
...@@ -1334,7 +1335,7 @@ int cgroup_bpf_prog_query(const union bpf_attr *attr, ...@@ -1334,7 +1335,7 @@ int cgroup_bpf_prog_query(const union bpf_attr *attr,
* __cgroup_bpf_run_filter_skb() - Run a program for packet filtering * __cgroup_bpf_run_filter_skb() - Run a program for packet filtering
* @sk: The socket sending or receiving traffic * @sk: The socket sending or receiving traffic
* @skb: The skb that is being sent or received * @skb: The skb that is being sent or received
* @type: The type of program to be executed * @atype: The type of program to be executed
* *
* If no socket is passed, or the socket is not of type INET or INET6, * If no socket is passed, or the socket is not of type INET or INET6,
* this function does nothing and returns 0. * this function does nothing and returns 0.
...@@ -1424,7 +1425,7 @@ EXPORT_SYMBOL(__cgroup_bpf_run_filter_skb); ...@@ -1424,7 +1425,7 @@ EXPORT_SYMBOL(__cgroup_bpf_run_filter_skb);
/** /**
* __cgroup_bpf_run_filter_sk() - Run a program on a sock * __cgroup_bpf_run_filter_sk() - Run a program on a sock
* @sk: sock structure to manipulate * @sk: sock structure to manipulate
* @type: The type of program to be executed * @atype: The type of program to be executed
* *
* socket is passed is expected to be of type INET or INET6. * socket is passed is expected to be of type INET or INET6.
* *
...@@ -1449,7 +1450,7 @@ EXPORT_SYMBOL(__cgroup_bpf_run_filter_sk); ...@@ -1449,7 +1450,7 @@ EXPORT_SYMBOL(__cgroup_bpf_run_filter_sk);
* provided by user sockaddr * provided by user sockaddr
* @sk: sock struct that will use sockaddr * @sk: sock struct that will use sockaddr
* @uaddr: sockaddr struct provided by user * @uaddr: sockaddr struct provided by user
* @type: The type of program to be executed * @atype: The type of program to be executed
* @t_ctx: Pointer to attach type specific context * @t_ctx: Pointer to attach type specific context
* @flags: Pointer to u32 which contains higher bits of BPF program * @flags: Pointer to u32 which contains higher bits of BPF program
* return value (OR'ed together). * return value (OR'ed together).
...@@ -1496,7 +1497,7 @@ EXPORT_SYMBOL(__cgroup_bpf_run_filter_sock_addr); ...@@ -1496,7 +1497,7 @@ EXPORT_SYMBOL(__cgroup_bpf_run_filter_sock_addr);
* @sock_ops: bpf_sock_ops_kern struct to pass to program. Contains * @sock_ops: bpf_sock_ops_kern struct to pass to program. Contains
* sk with connection information (IP addresses, etc.) May not contain * sk with connection information (IP addresses, etc.) May not contain
* cgroup info if it is a req sock. * cgroup info if it is a req sock.
* @type: The type of program to be executed * @atype: The type of program to be executed
* *
* socket passed is expected to be of type INET or INET6. * socket passed is expected to be of type INET or INET6.
* *
...@@ -1670,7 +1671,7 @@ const struct bpf_verifier_ops cg_dev_verifier_ops = { ...@@ -1670,7 +1671,7 @@ const struct bpf_verifier_ops cg_dev_verifier_ops = {
* @ppos: value-result argument: value is position at which read from or write * @ppos: value-result argument: value is position at which read from or write
* to sysctl is happening, result is new position if program overrode it, * to sysctl is happening, result is new position if program overrode it,
* initial value otherwise * initial value otherwise
* @type: type of program to be executed * @atype: type of program to be executed
* *
* Program is run when sysctl is being accessed, either read or written, and * Program is run when sysctl is being accessed, either read or written, and
* can allow or deny such access. * can allow or deny such access.
......
...@@ -459,8 +459,7 @@ static void notrace irq_work_raise(struct bpf_mem_cache *c) ...@@ -459,8 +459,7 @@ static void notrace irq_work_raise(struct bpf_mem_cache *c)
* Typical case will be between 11K and 116K closer to 11K. * Typical case will be between 11K and 116K closer to 11K.
* bpf progs can and should share bpf_mem_cache when possible. * bpf progs can and should share bpf_mem_cache when possible.
*/ */
static void init_refill_work(struct bpf_mem_cache *c)
static void prefill_mem_cache(struct bpf_mem_cache *c, int cpu)
{ {
init_irq_work(&c->refill_work, bpf_mem_refill); init_irq_work(&c->refill_work, bpf_mem_refill);
if (c->unit_size <= 256) { if (c->unit_size <= 256) {
...@@ -476,7 +475,10 @@ static void prefill_mem_cache(struct bpf_mem_cache *c, int cpu) ...@@ -476,7 +475,10 @@ static void prefill_mem_cache(struct bpf_mem_cache *c, int cpu)
c->high_watermark = max(96 * 256 / c->unit_size, 3); c->high_watermark = max(96 * 256 / c->unit_size, 3);
} }
c->batch = max((c->high_watermark - c->low_watermark) / 4 * 3, 1); c->batch = max((c->high_watermark - c->low_watermark) / 4 * 3, 1);
}
static void prefill_mem_cache(struct bpf_mem_cache *c, int cpu)
{
/* To avoid consuming memory assume that 1st run of bpf /* To avoid consuming memory assume that 1st run of bpf
* prog won't be doing more than 4 map_update_elem from * prog won't be doing more than 4 map_update_elem from
* irq disabled region * irq disabled region
...@@ -484,6 +486,31 @@ static void prefill_mem_cache(struct bpf_mem_cache *c, int cpu) ...@@ -484,6 +486,31 @@ static void prefill_mem_cache(struct bpf_mem_cache *c, int cpu)
alloc_bulk(c, c->unit_size <= 256 ? 4 : 1, cpu_to_node(cpu), false); alloc_bulk(c, c->unit_size <= 256 ? 4 : 1, cpu_to_node(cpu), false);
} }
static int check_obj_size(struct bpf_mem_cache *c, unsigned int idx)
{
struct llist_node *first;
unsigned int obj_size;
/* For per-cpu allocator, the size of free objects in free list doesn't
* match with unit_size and now there is no way to get the size of
* per-cpu pointer saved in free object, so just skip the checking.
*/
if (c->percpu_size)
return 0;
first = c->free_llist.first;
if (!first)
return 0;
obj_size = ksize(first);
if (obj_size != c->unit_size) {
WARN_ONCE(1, "bpf_mem_cache[%u]: unexpected object size %u, expect %u\n",
idx, obj_size, c->unit_size);
return -EINVAL;
}
return 0;
}
/* When size != 0 bpf_mem_cache for each cpu. /* When size != 0 bpf_mem_cache for each cpu.
* This is typical bpf hash map use case when all elements have equal size. * This is typical bpf hash map use case when all elements have equal size.
* *
...@@ -494,10 +521,10 @@ static void prefill_mem_cache(struct bpf_mem_cache *c, int cpu) ...@@ -494,10 +521,10 @@ static void prefill_mem_cache(struct bpf_mem_cache *c, int cpu)
int bpf_mem_alloc_init(struct bpf_mem_alloc *ma, int size, bool percpu) int bpf_mem_alloc_init(struct bpf_mem_alloc *ma, int size, bool percpu)
{ {
static u16 sizes[NUM_CACHES] = {96, 192, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096}; static u16 sizes[NUM_CACHES] = {96, 192, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096};
int cpu, i, err, unit_size, percpu_size = 0;
struct bpf_mem_caches *cc, __percpu *pcc; struct bpf_mem_caches *cc, __percpu *pcc;
struct bpf_mem_cache *c, __percpu *pc; struct bpf_mem_cache *c, __percpu *pc;
struct obj_cgroup *objcg = NULL; struct obj_cgroup *objcg = NULL;
int cpu, i, unit_size, percpu_size = 0;
if (size) { if (size) {
pc = __alloc_percpu_gfp(sizeof(*pc), 8, GFP_KERNEL); pc = __alloc_percpu_gfp(sizeof(*pc), 8, GFP_KERNEL);
...@@ -521,6 +548,7 @@ int bpf_mem_alloc_init(struct bpf_mem_alloc *ma, int size, bool percpu) ...@@ -521,6 +548,7 @@ int bpf_mem_alloc_init(struct bpf_mem_alloc *ma, int size, bool percpu)
c->objcg = objcg; c->objcg = objcg;
c->percpu_size = percpu_size; c->percpu_size = percpu_size;
c->tgt = c; c->tgt = c;
init_refill_work(c);
prefill_mem_cache(c, cpu); prefill_mem_cache(c, cpu);
} }
ma->cache = pc; ma->cache = pc;
...@@ -534,6 +562,7 @@ int bpf_mem_alloc_init(struct bpf_mem_alloc *ma, int size, bool percpu) ...@@ -534,6 +562,7 @@ int bpf_mem_alloc_init(struct bpf_mem_alloc *ma, int size, bool percpu)
pcc = __alloc_percpu_gfp(sizeof(*cc), 8, GFP_KERNEL); pcc = __alloc_percpu_gfp(sizeof(*cc), 8, GFP_KERNEL);
if (!pcc) if (!pcc)
return -ENOMEM; return -ENOMEM;
err = 0;
#ifdef CONFIG_MEMCG_KMEM #ifdef CONFIG_MEMCG_KMEM
objcg = get_obj_cgroup_from_current(); objcg = get_obj_cgroup_from_current();
#endif #endif
...@@ -544,11 +573,30 @@ int bpf_mem_alloc_init(struct bpf_mem_alloc *ma, int size, bool percpu) ...@@ -544,11 +573,30 @@ int bpf_mem_alloc_init(struct bpf_mem_alloc *ma, int size, bool percpu)
c->unit_size = sizes[i]; c->unit_size = sizes[i];
c->objcg = objcg; c->objcg = objcg;
c->tgt = c; c->tgt = c;
init_refill_work(c);
/* Another bpf_mem_cache will be used when allocating
* c->unit_size in bpf_mem_alloc(), so doesn't prefill
* for the bpf_mem_cache because these free objects will
* never be used.
*/
if (i != bpf_mem_cache_idx(c->unit_size))
continue;
prefill_mem_cache(c, cpu); prefill_mem_cache(c, cpu);
err = check_obj_size(c, i);
if (err)
goto out;
} }
} }
out:
ma->caches = pcc; ma->caches = pcc;
return 0; /* refill_work is either zeroed or initialized, so it is safe to
* call irq_work_sync().
*/
if (err)
bpf_mem_alloc_destroy(ma);
return err;
} }
static void drain_mem_cache(struct bpf_mem_cache *c) static void drain_mem_cache(struct bpf_mem_cache *c)
...@@ -916,3 +964,41 @@ void notrace *bpf_mem_cache_alloc_flags(struct bpf_mem_alloc *ma, gfp_t flags) ...@@ -916,3 +964,41 @@ void notrace *bpf_mem_cache_alloc_flags(struct bpf_mem_alloc *ma, gfp_t flags)
return !ret ? NULL : ret + LLIST_NODE_SZ; return !ret ? NULL : ret + LLIST_NODE_SZ;
} }
/* Most of the logic is taken from setup_kmalloc_cache_index_table() */
static __init int bpf_mem_cache_adjust_size(void)
{
unsigned int size, index;
/* Normally KMALLOC_MIN_SIZE is 8-bytes, but it can be
* up-to 256-bytes.
*/
size = KMALLOC_MIN_SIZE;
if (size <= 192)
index = size_index[(size - 1) / 8];
else
index = fls(size - 1) - 1;
for (size = 8; size < KMALLOC_MIN_SIZE && size <= 192; size += 8)
size_index[(size - 1) / 8] = index;
/* The minimal alignment is 64-bytes, so disable 96-bytes cache and
* use 128-bytes cache instead.
*/
if (KMALLOC_MIN_SIZE >= 64) {
index = size_index[(128 - 1) / 8];
for (size = 64 + 8; size <= 96; size += 8)
size_index[(size - 1) / 8] = index;
}
/* The minimal alignment is 128-bytes, so disable 192-bytes cache and
* use 256-bytes cache instead.
*/
if (KMALLOC_MIN_SIZE >= 128) {
index = fls(256 - 1) - 1;
for (size = 128 + 8; size <= 192; size += 8)
size_index[(size - 1) / 8] = index;
}
return 0;
}
subsys_initcall(bpf_mem_cache_adjust_size);
...@@ -199,12 +199,14 @@ static int __bpf_prog_dev_bound_init(struct bpf_prog *prog, struct net_device *n ...@@ -199,12 +199,14 @@ static int __bpf_prog_dev_bound_init(struct bpf_prog *prog, struct net_device *n
offload->netdev = netdev; offload->netdev = netdev;
ondev = bpf_offload_find_netdev(offload->netdev); ondev = bpf_offload_find_netdev(offload->netdev);
if (!ondev) { /* When program is offloaded require presence of "true"
if (bpf_prog_is_offloaded(prog->aux)) { * bpf_offload_netdev, avoid the one created for !ondev case below.
*/
if (bpf_prog_is_offloaded(prog->aux) && (!ondev || !ondev->offdev)) {
err = -EINVAL; err = -EINVAL;
goto err_free; goto err_free;
} }
if (!ondev) {
/* When only binding to the device, explicitly /* When only binding to the device, explicitly
* create an entry in the hashtable. * create an entry in the hashtable.
*/ */
......
...@@ -98,7 +98,12 @@ static long __queue_map_get(struct bpf_map *map, void *value, bool delete) ...@@ -98,7 +98,12 @@ static long __queue_map_get(struct bpf_map *map, void *value, bool delete)
int err = 0; int err = 0;
void *ptr; void *ptr;
if (in_nmi()) {
if (!raw_spin_trylock_irqsave(&qs->lock, flags))
return -EBUSY;
} else {
raw_spin_lock_irqsave(&qs->lock, flags); raw_spin_lock_irqsave(&qs->lock, flags);
}
if (queue_stack_map_is_empty(qs)) { if (queue_stack_map_is_empty(qs)) {
memset(value, 0, qs->map.value_size); memset(value, 0, qs->map.value_size);
...@@ -128,7 +133,12 @@ static long __stack_map_get(struct bpf_map *map, void *value, bool delete) ...@@ -128,7 +133,12 @@ static long __stack_map_get(struct bpf_map *map, void *value, bool delete)
void *ptr; void *ptr;
u32 index; u32 index;
if (in_nmi()) {
if (!raw_spin_trylock_irqsave(&qs->lock, flags))
return -EBUSY;
} else {
raw_spin_lock_irqsave(&qs->lock, flags); raw_spin_lock_irqsave(&qs->lock, flags);
}
if (queue_stack_map_is_empty(qs)) { if (queue_stack_map_is_empty(qs)) {
memset(value, 0, qs->map.value_size); memset(value, 0, qs->map.value_size);
...@@ -193,7 +203,12 @@ static long queue_stack_map_push_elem(struct bpf_map *map, void *value, ...@@ -193,7 +203,12 @@ static long queue_stack_map_push_elem(struct bpf_map *map, void *value,
if (flags & BPF_NOEXIST || flags > BPF_EXIST) if (flags & BPF_NOEXIST || flags > BPF_EXIST)
return -EINVAL; return -EINVAL;
if (in_nmi()) {
if (!raw_spin_trylock_irqsave(&qs->lock, irq_flags))
return -EBUSY;
} else {
raw_spin_lock_irqsave(&qs->lock, irq_flags); raw_spin_lock_irqsave(&qs->lock, irq_flags);
}
if (queue_stack_map_is_full(qs)) { if (queue_stack_map_is_full(qs)) {
if (!replace) { if (!replace) {
......
...@@ -2853,6 +2853,17 @@ static int get_modules_for_addrs(struct module ***mods, unsigned long *addrs, u3 ...@@ -2853,6 +2853,17 @@ static int get_modules_for_addrs(struct module ***mods, unsigned long *addrs, u3
return arr.mods_cnt; return arr.mods_cnt;
} }
static int addrs_check_error_injection_list(unsigned long *addrs, u32 cnt)
{
u32 i;
for (i = 0; i < cnt; i++) {
if (!within_error_injection_list(addrs[i]))
return -EINVAL;
}
return 0;
}
int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *prog) int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
{ {
struct bpf_kprobe_multi_link *link = NULL; struct bpf_kprobe_multi_link *link = NULL;
...@@ -2930,6 +2941,11 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr ...@@ -2930,6 +2941,11 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
goto error; goto error;
} }
if (prog->kprobe_override && addrs_check_error_injection_list(addrs, cnt)) {
err = -EINVAL;
goto error;
}
link = kzalloc(sizeof(*link), GFP_KERNEL); link = kzalloc(sizeof(*link), GFP_KERNEL);
if (!link) { if (!link) {
err = -ENOMEM; err = -ENOMEM;
...@@ -3207,9 +3223,11 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr ...@@ -3207,9 +3223,11 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
rcu_read_lock(); rcu_read_lock();
task = get_pid_task(find_vpid(pid), PIDTYPE_PID); task = get_pid_task(find_vpid(pid), PIDTYPE_PID);
rcu_read_unlock(); rcu_read_unlock();
if (!task) if (!task) {
err = -ESRCH;
goto error_path_put; goto error_path_put;
} }
}
err = -ENOMEM; err = -ENOMEM;
......
...@@ -381,6 +381,8 @@ __bpf_kfunc struct nf_conn *bpf_ct_insert_entry(struct nf_conn___init *nfct_i) ...@@ -381,6 +381,8 @@ __bpf_kfunc struct nf_conn *bpf_ct_insert_entry(struct nf_conn___init *nfct_i)
struct nf_conn *nfct = (struct nf_conn *)nfct_i; struct nf_conn *nfct = (struct nf_conn *)nfct_i;
int err; int err;
if (!nf_ct_is_confirmed(nfct))
nfct->timeout += nfct_time_stamp;
nfct->status |= IPS_CONFIRMED; nfct->status |= IPS_CONFIRMED;
err = nf_conntrack_hash_check_insert(nfct); err = nf_conntrack_hash_check_insert(nfct);
if (err < 0) { if (err < 0) {
......
...@@ -38,7 +38,7 @@ asm( \ ...@@ -38,7 +38,7 @@ asm( \
____BTF_ID(symbol) ____BTF_ID(symbol)
#define __ID(prefix) \ #define __ID(prefix) \
__PASTE(prefix, __COUNTER__) __PASTE(__PASTE(prefix, __COUNTER__), __LINE__)
/* /*
* The BTF_ID defines unique symbol for each ID pointing * The BTF_ID defines unique symbol for each ID pointing
......
...@@ -1962,7 +1962,9 @@ union bpf_attr { ...@@ -1962,7 +1962,9 @@ union bpf_attr {
* performed again, if the helper is used in combination with * performed again, if the helper is used in combination with
* direct packet access. * direct packet access.
* Return * Return
* 0 on success, or a negative error in case of failure. * 0 on success, or a negative error in case of failure. Positive
* error indicates a potential drop or congestion in the target
* device. The particular positive error codes are not defined.
* *
* u64 bpf_get_current_pid_tgid(void) * u64 bpf_get_current_pid_tgid(void)
* Description * Description
......
bpf_cookie/multi_kprobe_attach_api # kprobe_multi_link_api_subtest:FAIL:fentry_raw_skel_load unexpected error: -3 bpf_cookie/multi_kprobe_attach_api # kprobe_multi_link_api_subtest:FAIL:fentry_raw_skel_load unexpected error: -3
bpf_cookie/multi_kprobe_link_api # kprobe_multi_link_api_subtest:FAIL:fentry_raw_skel_load unexpected error: -3 bpf_cookie/multi_kprobe_link_api # kprobe_multi_link_api_subtest:FAIL:fentry_raw_skel_load unexpected error: -3
fexit_sleep # The test never returns. The remaining tests cannot start. fexit_sleep # The test never returns. The remaining tests cannot start.
kprobe_multi_bench_attach # bpf_program__attach_kprobe_multi_opts unexpected error: -95 kprobe_multi_bench_attach # needs CONFIG_FPROBE
kprobe_multi_test/attach_api_addrs # bpf_program__attach_kprobe_multi_opts unexpected error: -95 kprobe_multi_test # needs CONFIG_FPROBE
kprobe_multi_test/attach_api_pattern # bpf_program__attach_kprobe_multi_opts unexpected error: -95
kprobe_multi_test/attach_api_syms # bpf_program__attach_kprobe_multi_opts unexpected error: -95
kprobe_multi_test/bench_attach # bpf_program__attach_kprobe_multi_opts unexpected error: -95
kprobe_multi_test/link_api_addrs # link_fd unexpected link_fd: actual -95 < expected 0
kprobe_multi_test/link_api_syms # link_fd unexpected link_fd: actual -95 < expected 0
kprobe_multi_test/skel_api # libbpf: failed to load BPF skeleton 'kprobe_multi': -3
module_attach # prog 'kprobe_multi': failed to auto-attach: -95 module_attach # prog 'kprobe_multi': failed to auto-attach: -95
fentry_test/fentry_many_args # fentry_many_args:FAIL:fentry_many_args_attach unexpected error: -524 fentry_test/fentry_many_args # fentry_many_args:FAIL:fentry_many_args_attach unexpected error: -524
fexit_test/fexit_many_args # fexit_many_args:FAIL:fexit_many_args_attach unexpected error: -524 fexit_test/fexit_many_args # fexit_many_args:FAIL:fexit_many_args_attach unexpected error: -524
......
...@@ -4,6 +4,7 @@ CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y ...@@ -4,6 +4,7 @@ CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
CONFIG_BPF=y CONFIG_BPF=y
CONFIG_BPF_EVENTS=y CONFIG_BPF_EVENTS=y
CONFIG_BPF_JIT=y CONFIG_BPF_JIT=y
CONFIG_BPF_KPROBE_OVERRIDE=y
CONFIG_BPF_LIRC_MODE2=y CONFIG_BPF_LIRC_MODE2=y
CONFIG_BPF_LSM=y CONFIG_BPF_LSM=y
CONFIG_BPF_STREAM_PARSER=y CONFIG_BPF_STREAM_PARSER=y
......
...@@ -20,7 +20,6 @@ CONFIG_BLK_DEV_THROTTLING=y ...@@ -20,7 +20,6 @@ CONFIG_BLK_DEV_THROTTLING=y
CONFIG_BONDING=y CONFIG_BONDING=y
CONFIG_BOOTTIME_TRACING=y CONFIG_BOOTTIME_TRACING=y
CONFIG_BPF_JIT_ALWAYS_ON=y CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_BPF_KPROBE_OVERRIDE=y
CONFIG_BPF_PRELOAD=y CONFIG_BPF_PRELOAD=y
CONFIG_BPF_PRELOAD_UMD=y CONFIG_BPF_PRELOAD_UMD=y
CONFIG_BPFILTER=y CONFIG_BPFILTER=y
......
...@@ -24,6 +24,7 @@ void test_empty_skb(void) ...@@ -24,6 +24,7 @@ void test_empty_skb(void)
int *ifindex; int *ifindex;
int err; int err;
int ret; int ret;
int lwt_egress_ret; /* expected retval at lwt/egress */
bool success_on_tc; bool success_on_tc;
} tests[] = { } tests[] = {
/* Empty packets are always rejected. */ /* Empty packets are always rejected. */
...@@ -57,6 +58,7 @@ void test_empty_skb(void) ...@@ -57,6 +58,7 @@ void test_empty_skb(void)
.data_size_in = sizeof(eth_hlen), .data_size_in = sizeof(eth_hlen),
.ifindex = &veth_ifindex, .ifindex = &veth_ifindex,
.ret = -ERANGE, .ret = -ERANGE,
.lwt_egress_ret = -ERANGE,
.success_on_tc = true, .success_on_tc = true,
}, },
{ {
...@@ -70,6 +72,7 @@ void test_empty_skb(void) ...@@ -70,6 +72,7 @@ void test_empty_skb(void)
.data_size_in = sizeof(eth_hlen), .data_size_in = sizeof(eth_hlen),
.ifindex = &ipip_ifindex, .ifindex = &ipip_ifindex,
.ret = -ERANGE, .ret = -ERANGE,
.lwt_egress_ret = -ERANGE,
}, },
/* ETH_HLEN+1-sized packet should be redirected. */ /* ETH_HLEN+1-sized packet should be redirected. */
...@@ -79,6 +82,7 @@ void test_empty_skb(void) ...@@ -79,6 +82,7 @@ void test_empty_skb(void)
.data_in = eth_hlen_pp, .data_in = eth_hlen_pp,
.data_size_in = sizeof(eth_hlen_pp), .data_size_in = sizeof(eth_hlen_pp),
.ifindex = &veth_ifindex, .ifindex = &veth_ifindex,
.lwt_egress_ret = 1, /* veth_xmit NET_XMIT_DROP */
}, },
{ {
.msg = "ipip ETH_HLEN+1 packet ingress", .msg = "ipip ETH_HLEN+1 packet ingress",
...@@ -108,8 +112,12 @@ void test_empty_skb(void) ...@@ -108,8 +112,12 @@ void test_empty_skb(void)
for (i = 0; i < ARRAY_SIZE(tests); i++) { for (i = 0; i < ARRAY_SIZE(tests); i++) {
bpf_object__for_each_program(prog, bpf_obj->obj) { bpf_object__for_each_program(prog, bpf_obj->obj) {
char buf[128]; bool at_egress = strstr(bpf_program__name(prog), "egress") != NULL;
bool at_tc = !strncmp(bpf_program__section_name(prog), "tc", 2); bool at_tc = !strncmp(bpf_program__section_name(prog), "tc", 2);
int expected_ret;
char buf[128];
expected_ret = at_egress && !at_tc ? tests[i].lwt_egress_ret : tests[i].ret;
tattr.data_in = tests[i].data_in; tattr.data_in = tests[i].data_in;
tattr.data_size_in = tests[i].data_size_in; tattr.data_size_in = tests[i].data_size_in;
...@@ -128,7 +136,7 @@ void test_empty_skb(void) ...@@ -128,7 +136,7 @@ void test_empty_skb(void)
if (at_tc && tests[i].success_on_tc) if (at_tc && tests[i].success_on_tc)
ASSERT_GE(bpf_obj->bss->ret, 0, buf); ASSERT_GE(bpf_obj->bss->ret, 0, buf);
else else
ASSERT_EQ(bpf_obj->bss->ret, tests[i].ret, buf); ASSERT_EQ(bpf_obj->bss->ret, expected_ret, buf);
} }
} }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "kprobe_multi.skel.h" #include "kprobe_multi.skel.h"
#include "trace_helpers.h" #include "trace_helpers.h"
#include "kprobe_multi_empty.skel.h" #include "kprobe_multi_empty.skel.h"
#include "kprobe_multi_override.skel.h"
#include "bpf/libbpf_internal.h" #include "bpf/libbpf_internal.h"
#include "bpf/hashmap.h" #include "bpf/hashmap.h"
...@@ -453,6 +454,40 @@ static void test_kprobe_multi_bench_attach(bool kernel) ...@@ -453,6 +454,40 @@ static void test_kprobe_multi_bench_attach(bool kernel)
} }
} }
static void test_attach_override(void)
{
struct kprobe_multi_override *skel = NULL;
struct bpf_link *link = NULL;
skel = kprobe_multi_override__open_and_load();
if (!ASSERT_OK_PTR(skel, "kprobe_multi_empty__open_and_load"))
goto cleanup;
/* The test_override calls bpf_override_return so it should fail
* to attach to bpf_fentry_test1 function, which is not on error
* injection list.
*/
link = bpf_program__attach_kprobe_multi_opts(skel->progs.test_override,
"bpf_fentry_test1", NULL);
if (!ASSERT_ERR_PTR(link, "override_attached_bpf_fentry_test1")) {
bpf_link__destroy(link);
goto cleanup;
}
/* The should_fail_bio function is on error injection list,
* attach should succeed.
*/
link = bpf_program__attach_kprobe_multi_opts(skel->progs.test_override,
"should_fail_bio", NULL);
if (!ASSERT_OK_PTR(link, "override_attached_should_fail_bio"))
goto cleanup;
bpf_link__destroy(link);
cleanup:
kprobe_multi_override__destroy(skel);
}
void serial_test_kprobe_multi_bench_attach(void) void serial_test_kprobe_multi_bench_attach(void)
{ {
if (test__start_subtest("kernel")) if (test__start_subtest("kernel"))
...@@ -480,4 +515,6 @@ void test_kprobe_multi_test(void) ...@@ -480,4 +515,6 @@ void test_kprobe_multi_test(void)
test_attach_api_syms(); test_attach_api_syms();
if (test__start_subtest("attach_api_fails")) if (test__start_subtest("attach_api_fails"))
test_attach_api_fails(); test_attach_api_fails();
if (test__start_subtest("attach_override"))
test_attach_override();
} }
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2023. Huawei Technologies Co., Ltd */
#define _GNU_SOURCE
#include <sched.h>
#include <pthread.h>
#include <stdbool.h>
#include <bpf/btf.h>
#include <test_progs.h>
#include "test_bpf_ma.skel.h"
void test_test_bpf_ma(void)
{
struct test_bpf_ma *skel;
struct btf *btf;
int i, err;
skel = test_bpf_ma__open();
if (!ASSERT_OK_PTR(skel, "open"))
return;
btf = bpf_object__btf(skel->obj);
if (!ASSERT_OK_PTR(btf, "btf"))
goto out;
for (i = 0; i < ARRAY_SIZE(skel->rodata->data_sizes); i++) {
char name[32];
int id;
snprintf(name, sizeof(name), "bin_data_%u", skel->rodata->data_sizes[i]);
id = btf__find_by_name_kind(btf, name, BTF_KIND_STRUCT);
if (!ASSERT_GT(id, 0, "bin_data"))
goto out;
skel->rodata->data_btf_ids[i] = id;
}
err = test_bpf_ma__load(skel);
if (!ASSERT_OK(err, "load"))
goto out;
err = test_bpf_ma__attach(skel);
if (!ASSERT_OK(err, "attach"))
goto out;
skel->bss->pid = getpid();
usleep(1);
ASSERT_OK(skel->bss->err, "test error");
out:
test_bpf_ma__destroy(skel);
}
// SPDX-License-Identifier: GPL-2.0
#include <net/if.h>
#include <test_progs.h>
#include <network_helpers.h>
#define LOCAL_NETNS "xdp_dev_bound_only_netns"
static int load_dummy_prog(char *name, __u32 ifindex, __u32 flags)
{
struct bpf_insn insns[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN() };
LIBBPF_OPTS(bpf_prog_load_opts, opts);
opts.prog_flags = flags;
opts.prog_ifindex = ifindex;
return bpf_prog_load(BPF_PROG_TYPE_XDP, name, "GPL", insns, ARRAY_SIZE(insns), &opts);
}
/* A test case for bpf_offload_netdev->offload handling bug:
* - create a veth device (does not support offload);
* - create a device bound XDP program with BPF_F_XDP_DEV_BOUND_ONLY flag
* (such programs are not offloaded);
* - create a device bound XDP program without flags (such programs are offloaded).
* This might lead to 'BUG: kernel NULL pointer dereference'.
*/
void test_xdp_dev_bound_only_offdev(void)
{
struct nstoken *tok = NULL;
__u32 ifindex;
int fd1 = -1;
int fd2 = -1;
SYS(out, "ip netns add " LOCAL_NETNS);
tok = open_netns(LOCAL_NETNS);
if (!ASSERT_OK_PTR(tok, "open_netns"))
goto out;
SYS(out, "ip link add eth42 type veth");
ifindex = if_nametoindex("eth42");
if (!ASSERT_NEQ(ifindex, 0, "if_nametoindex")) {
perror("if_nametoindex");
goto out;
}
fd1 = load_dummy_prog("dummy1", ifindex, BPF_F_XDP_DEV_BOUND_ONLY);
if (!ASSERT_GE(fd1, 0, "load_dummy_prog #1")) {
perror("load_dummy_prog #1");
goto out;
}
/* Program with ifindex is considered offloaded, however veth
* does not support offload => error should be reported.
*/
fd2 = load_dummy_prog("dummy2", ifindex, 0);
ASSERT_EQ(fd2, -EINVAL, "load_dummy_prog #2 (offloaded)");
out:
close(fd1);
close(fd2);
close_netns(tok);
/* eth42 was added inside netns, removing the netns will
* also remove eth42 veth pair.
*/
SYS_NOFAIL("ip netns del " LOCAL_NETNS);
}
// SPDX-License-Identifier: GPL-2.0
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
char _license[] SEC("license") = "GPL";
SEC("kprobe.multi")
int test_override(struct pt_regs *ctx)
{
bpf_override_return(ctx, 123);
return 0;
}
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2023. Huawei Technologies Co., Ltd */
#include <vmlinux.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_helpers.h>
#include "bpf_experimental.h"
#include "bpf_misc.h"
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#endif
struct generic_map_value {
void *data;
};
char _license[] SEC("license") = "GPL";
const unsigned int data_sizes[] = {8, 16, 32, 64, 96, 128, 192, 256, 512, 1024, 2048, 4096};
const volatile unsigned int data_btf_ids[ARRAY_SIZE(data_sizes)] = {};
int err = 0;
int pid = 0;
#define DEFINE_ARRAY_WITH_KPTR(_size) \
struct bin_data_##_size { \
char data[_size - sizeof(void *)]; \
}; \
struct map_value_##_size { \
struct bin_data_##_size __kptr * data; \
/* To emit BTF info for bin_data_xx */ \
struct bin_data_##_size not_used; \
}; \
struct { \
__uint(type, BPF_MAP_TYPE_ARRAY); \
__type(key, int); \
__type(value, struct map_value_##_size); \
__uint(max_entries, 128); \
} array_##_size SEC(".maps");
static __always_inline void batch_alloc_free(struct bpf_map *map, unsigned int batch,
unsigned int idx)
{
struct generic_map_value *value;
unsigned int i, key;
void *old, *new;
for (i = 0; i < batch; i++) {
key = i;
value = bpf_map_lookup_elem(map, &key);
if (!value) {
err = 1;
return;
}
new = bpf_obj_new_impl(data_btf_ids[idx], NULL);
if (!new) {
err = 2;
return;
}
old = bpf_kptr_xchg(&value->data, new);
if (old) {
bpf_obj_drop(old);
err = 3;
return;
}
}
for (i = 0; i < batch; i++) {
key = i;
value = bpf_map_lookup_elem(map, &key);
if (!value) {
err = 4;
return;
}
old = bpf_kptr_xchg(&value->data, NULL);
if (!old) {
err = 5;
return;
}
bpf_obj_drop(old);
}
}
#define CALL_BATCH_ALLOC_FREE(size, batch, idx) \
batch_alloc_free((struct bpf_map *)(&array_##size), batch, idx)
DEFINE_ARRAY_WITH_KPTR(8);
DEFINE_ARRAY_WITH_KPTR(16);
DEFINE_ARRAY_WITH_KPTR(32);
DEFINE_ARRAY_WITH_KPTR(64);
DEFINE_ARRAY_WITH_KPTR(96);
DEFINE_ARRAY_WITH_KPTR(128);
DEFINE_ARRAY_WITH_KPTR(192);
DEFINE_ARRAY_WITH_KPTR(256);
DEFINE_ARRAY_WITH_KPTR(512);
DEFINE_ARRAY_WITH_KPTR(1024);
DEFINE_ARRAY_WITH_KPTR(2048);
DEFINE_ARRAY_WITH_KPTR(4096);
SEC("fentry/" SYS_PREFIX "sys_nanosleep")
int test_bpf_mem_alloc_free(void *ctx)
{
if ((u32)bpf_get_current_pid_tgid() != pid)
return 0;
/* Alloc 128 8-bytes objects in batch to trigger refilling,
* then free 128 8-bytes objects in batch to trigger freeing.
*/
CALL_BATCH_ALLOC_FREE(8, 128, 0);
CALL_BATCH_ALLOC_FREE(16, 128, 1);
CALL_BATCH_ALLOC_FREE(32, 128, 2);
CALL_BATCH_ALLOC_FREE(64, 128, 3);
CALL_BATCH_ALLOC_FREE(96, 128, 4);
CALL_BATCH_ALLOC_FREE(128, 128, 5);
CALL_BATCH_ALLOC_FREE(192, 128, 6);
CALL_BATCH_ALLOC_FREE(256, 128, 7);
CALL_BATCH_ALLOC_FREE(512, 64, 8);
CALL_BATCH_ALLOC_FREE(1024, 32, 9);
CALL_BATCH_ALLOC_FREE(2048, 16, 10);
CALL_BATCH_ALLOC_FREE(4096, 8, 11);
return 0;
}
...@@ -1880,7 +1880,7 @@ int main(int argc, char **argv) ...@@ -1880,7 +1880,7 @@ int main(int argc, char **argv)
} }
} }
get_unpriv_disabled(); unpriv_disabled = get_unpriv_disabled();
if (unpriv && unpriv_disabled) { if (unpriv && unpriv_disabled) {
printf("Cannot run as unprivileged user with sysctl %s.\n", printf("Cannot run as unprivileged user with sysctl %s.\n",
UNPRIV_SYSCTL); UNPRIV_SYSCTL);
......
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