selftests/bpf: Add tests for tail calls with locks and refs
Add failure tests to ensure bugs don't slip through for tail calls and lingering locks, RCU sections, preemption disabled sections, and references prevent tail calls. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Link: https://lore.kernel.org/r/20241103225940.1408302-4-memxor@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
committed by
Alexei Starovoitov
parent
d402755ced
commit
711df091de
@@ -7,6 +7,7 @@
|
||||
#include "tailcall_bpf2bpf_hierarchy3.skel.h"
|
||||
#include "tailcall_freplace.skel.h"
|
||||
#include "tc_bpf2bpf.skel.h"
|
||||
#include "tailcall_fail.skel.h"
|
||||
|
||||
/* test_tailcall_1 checks basic functionality by patching multiple locations
|
||||
* in a single program for a single tail call slot with nop->jmp, jmp->nop
|
||||
@@ -1646,6 +1647,11 @@ out:
|
||||
tc_bpf2bpf__destroy(tc_skel);
|
||||
}
|
||||
|
||||
static void test_tailcall_failure()
|
||||
{
|
||||
RUN_TESTS(tailcall_fail);
|
||||
}
|
||||
|
||||
void test_tailcalls(void)
|
||||
{
|
||||
if (test__start_subtest("tailcall_1"))
|
||||
@@ -1698,4 +1704,6 @@ void test_tailcalls(void)
|
||||
test_tailcall_freplace();
|
||||
if (test__start_subtest("tailcall_bpf2bpf_freplace"))
|
||||
test_tailcall_bpf2bpf_freplace();
|
||||
if (test__start_subtest("tailcall_failure"))
|
||||
test_tailcall_failure();
|
||||
}
|
||||
|
||||
64
tools/testing/selftests/bpf/progs/tailcall_fail.c
Normal file
64
tools/testing/selftests/bpf/progs/tailcall_fail.c
Normal file
@@ -0,0 +1,64 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */
|
||||
#include <vmlinux.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_core_read.h>
|
||||
|
||||
#include "bpf_misc.h"
|
||||
#include "bpf_experimental.h"
|
||||
|
||||
extern void bpf_rcu_read_lock(void) __ksym;
|
||||
extern void bpf_rcu_read_unlock(void) __ksym;
|
||||
|
||||
#define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8)))
|
||||
|
||||
private(A) struct bpf_spin_lock lock;
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
|
||||
__uint(max_entries, 3);
|
||||
__uint(key_size, sizeof(__u32));
|
||||
__uint(value_size, sizeof(__u32));
|
||||
} jmp_table SEC(".maps");
|
||||
|
||||
SEC("?tc")
|
||||
__failure __msg("function calls are not allowed while holding a lock")
|
||||
int reject_tail_call_spin_lock(struct __sk_buff *ctx)
|
||||
{
|
||||
bpf_spin_lock(&lock);
|
||||
bpf_tail_call_static(ctx, &jmp_table, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("?tc")
|
||||
__failure __msg("tail_call cannot be used inside bpf_rcu_read_lock-ed region")
|
||||
int reject_tail_call_rcu_lock(struct __sk_buff *ctx)
|
||||
{
|
||||
bpf_rcu_read_lock();
|
||||
bpf_tail_call_static(ctx, &jmp_table, 0);
|
||||
bpf_rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("?tc")
|
||||
__failure __msg("tail_call cannot be used inside bpf_preempt_disable-ed region")
|
||||
int reject_tail_call_preempt_lock(struct __sk_buff *ctx)
|
||||
{
|
||||
bpf_guard_preempt();
|
||||
bpf_tail_call_static(ctx, &jmp_table, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("?tc")
|
||||
__failure __msg("tail_call would lead to reference leak")
|
||||
int reject_tail_call_ref(struct __sk_buff *ctx)
|
||||
{
|
||||
struct foo { int i; } *p;
|
||||
|
||||
p = bpf_obj_new(typeof(*p));
|
||||
bpf_tail_call_static(ctx, &jmp_table, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
Reference in New Issue
Block a user