Commit f11f7cf9 authored by Alexei Starovoitov's avatar Alexei Starovoitov
Browse files

Merge branch 'bpf-add-bpf_stream_print_stack-kfunc'

Emil Tsalapatis says:

====================
bpf: Add bpf_stream_print_stack kfunc

Add a new bpf_stream_print_stack kfunc for printing a BPF program stack
into a BPF stream. Update the verifier to allow the new kfunc to be
called with BPF spinlocks held, along with bpf_stream_vprintk.

Patchset spun out of the larger libarena + ASAN patchset.
(https://lore.kernel.org/bpf/20260127181610.86376-1-emil@etsalapatis.com/)

Changeset:
	- Update bpf_stream_print_stack to take stream_id arg (Kumar)
	- Added selftest for the bpf_stream_print_stack
	- Add selftest for calling the streams kfuncs under lock

v2->v1: (https://lore.kernel.org/bpf/20260202193311.446717-1-emil@etsalapatis.com/

)
	- Updated Signed-off-by to be consistent with past submissions
	- Updated From email to be consistent with Signed-off-by

Acked-by: default avatarKumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: default avatarEmil Tsalapatis <emil@etsalapatis.com>
====================

Link: https://patch.msgid.link/20260203180424.14057-1-emil@etsalapatis.com


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents f941479a 4d99137e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -4562,6 +4562,7 @@ BTF_ID_FLAGS(func, bpf_strncasestr);
BTF_ID_FLAGS(func, bpf_cgroup_read_xattr, KF_RCU)
#endif
BTF_ID_FLAGS(func, bpf_stream_vprintk, KF_IMPLICIT_ARGS)
BTF_ID_FLAGS(func, bpf_stream_print_stack, KF_IMPLICIT_ARGS)
BTF_ID_FLAGS(func, bpf_task_work_schedule_signal, KF_IMPLICIT_ARGS)
BTF_ID_FLAGS(func, bpf_task_work_schedule_resume, KF_IMPLICIT_ARGS)
BTF_ID_FLAGS(func, bpf_dynptr_from_file)
+19 −0
Original line number Diff line number Diff line
@@ -245,6 +245,25 @@ __bpf_kfunc int bpf_stream_vprintk(int stream_id, const char *fmt__str, const vo
	return ret;
}

/* Directly trigger a stack dump from the program. */
__bpf_kfunc int bpf_stream_print_stack(int stream_id, struct bpf_prog_aux *aux)
{
	struct bpf_stream_stage ss;
	struct bpf_prog *prog;

	/* Make sure the stream ID is valid. */
	if (!bpf_stream_get(stream_id, aux))
		return -ENOENT;

	prog = aux->main_prog_aux->prog;

	bpf_stream_stage(ss, prog, stream_id, ({
		bpf_stream_dump_stack(ss);
	}));

	return 0;
}

__bpf_kfunc_end_defs();

/* Added kfunc to common_btf_ids */
+12 −1
Original line number Diff line number Diff line
@@ -12455,6 +12455,8 @@ enum special_kfunc_type {
	KF_bpf_arena_free_pages,
	KF_bpf_arena_reserve_pages,
	KF_bpf_session_is_return,
	KF_bpf_stream_vprintk,
	KF_bpf_stream_print_stack,
};
BTF_ID_LIST(special_kfunc_list)
@@ -12533,6 +12535,8 @@ BTF_ID(func, bpf_arena_alloc_pages)
BTF_ID(func, bpf_arena_free_pages)
BTF_ID(func, bpf_arena_reserve_pages)
BTF_ID(func, bpf_session_is_return)
BTF_ID(func, bpf_stream_vprintk)
BTF_ID(func, bpf_stream_print_stack)
static bool is_task_work_add_kfunc(u32 func_id)
{
@@ -12977,10 +12981,17 @@ static bool is_bpf_arena_kfunc(u32 btf_id)
	       btf_id == special_kfunc_list[KF_bpf_arena_reserve_pages];
}
static bool is_bpf_stream_kfunc(u32 btf_id)
{
	return btf_id == special_kfunc_list[KF_bpf_stream_vprintk] ||
	       btf_id == special_kfunc_list[KF_bpf_stream_print_stack];
}
static bool kfunc_spin_allowed(u32 btf_id)
{
	return is_bpf_graph_api_kfunc(btf_id) || is_bpf_iter_num_api_kfunc(btf_id) ||
	       is_bpf_res_spin_lock_kfunc(btf_id) || is_bpf_arena_kfunc(btf_id);
	       is_bpf_res_spin_lock_kfunc(btf_id) || is_bpf_arena_kfunc(btf_id) ||
	       is_bpf_stream_kfunc(btf_id);
}
static bool is_sync_callback_calling_kfunc(u32 btf_id)
+53 −0
Original line number Diff line number Diff line
@@ -42,6 +42,10 @@ int size;
u64 fault_addr;
void *arena_ptr;

#define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8)))

private(STREAM) struct bpf_spin_lock block;

SEC("syscall")
__success __retval(0)
int stream_exhaust(void *ctx)
@@ -234,4 +238,53 @@ int stream_arena_callback_fault(void *ctx)
	return 0;
}

SEC("syscall")
__arch_x86_64
__arch_arm64
__success __retval(0)
__stderr("CPU: {{[0-9]+}} UID: 0 PID: {{[0-9]+}} Comm: {{.*}}")
__stderr("Call trace:\n"
"{{([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n"
"|[ \t]+[^\n]+\n)*}}")
int stream_print_stack_kfunc(void *ctx)
{
	return bpf_stream_print_stack(BPF_STDERR);
}

SEC("syscall")
__success __retval(-2)
int stream_print_stack_invalid_id(void *ctx)
{
	/* Try to pass an invalid stream ID. */
	return bpf_stream_print_stack((enum bpf_stream_id)0xbadcafe);
}

SEC("syscall")
__arch_x86_64
__arch_arm64
__success __retval(0)
__stdout(_STR)
__stderr("CPU: {{[0-9]+}} UID: 0 PID: {{[0-9]+}} Comm: {{.*}}")
__stderr("Call trace:\n"
"{{([a-zA-Z_][a-zA-Z0-9_]*\\+0x[0-9a-fA-F]+/0x[0-9a-fA-F]+\n"
"|[ \t]+[^\n]+\n)*}}")
int stream_print_kfuncs_locked(void *ctx)
{
	int ret;

	bpf_spin_lock(&block);

	ret = bpf_stream_printk(BPF_STDOUT, _STR);
	if (ret)
		goto out;

	ret = bpf_stream_print_stack(BPF_STDERR);

out:
	bpf_spin_unlock(&block);

	return ret;
}


char _license[] SEC("license") = "GPL";