BPF Standard Streams
From: | Kumar Kartikeya Dwivedi <memxor-AT-gmail.com> | |
To: | bpf-AT-vger.kernel.org | |
Subject: | [PATCH bpf-next v1 00/11] BPF Standard Streams | |
Date: | Wed, 07 May 2025 10:17:09 -0700 | |
Message-ID: | <20250507171720.1958296-1-memxor@gmail.com> | |
Cc: | Alexei Starovoitov <ast-AT-kernel.org>, Andrii Nakryiko <andrii-AT-kernel.org>, Daniel Borkmann <daniel-AT-iogearbox.net>, Martin KaFai Lau <martin.lau-AT-kernel.org>, Eduard Zingerman <eddyz87-AT-gmail.com>, Emil Tsalapatis <emil-AT-etsalapatis.com>, Barret Rhoden <brho-AT-google.com>, Matt Bobrowski <mattbobrowski-AT-google.com>, kkd-AT-meta.com, kernel-team-AT-meta.com | |
Archive-link: | Article |
This set introduces a standard output interface with two streams, namely stdout and stderr, for BPF programs. The idea is that these streams will be written to by BPF programs and the kernel, and serve as standard interfaces for informing user space of any BPF runtime violations. Users can also utilize them for printing normal messages for debugging usage, as is the case with bpf_printk() and trace pipe interface. BPF programs and the kernel can use these streams to output messages. User space can dump these messages using bpftool. The stream interface itself is implemented using a lockless list, so that we can queue messages from any context. Every printk statement into the stream leads to memory allocation. Allocation itself relies on try_alloc_pages() to construct a bespoke bump allocator to carve out elements. If this fails, we finally give up and drop the message. See commit logs for more details. Three scenarios are covered: - Deadlocks and timeouts in rqspinlock. - Arena page faults. - Timeouts for may_goto. In each we provide the stack trace and source information for the offending BPF programs. Both the C source line and the file and line numbers are printed. The output format is as follows: ERROR: AA or ABBA deadlock detected for bpf_res_spin_lock Attempted lock = 0xff11000108f3a5e0 Total held locks = 1 Held lock[ 0] = 0xff11000108f3a5e0 CPU: 48 UID: 0 PID: 786 Comm: test_progs Call trace: bpf_stream_stage_dump_stack+0xb0/0xd0 bpf_prog_report_rqspinlock_violation+0x10b/0x130 bpf_res_spin_lock+0x8c/0xa0 bpf_prog_3699ea119d1f6ed8_foo+0xe5/0x140 if (!bpf_res_spin_lock(&v2->lock)) @ stream_bpftool.c:62 bpf_prog_9b324ec4a1b2a5c0_stream_bpftool_dump_prog_stream+0x7e/0x2d0 foo(stream); @ stream_bpftool.c:93 bpf_prog_test_run_syscall+0x102/0x240 __sys_bpf+0xd68/0x2bf0 __x64_sys_bpf+0x1e/0x30 do_syscall_64+0x68/0x140 entry_SYSCALL_64_after_hwframe+0x76/0x7e ERROR: Arena READ access at unmapped address 0xdeadbeef CPU: 48 UID: 0 PID: 786 Comm: test_progs Call trace: bpf_stream_stage_dump_stack+0xb0/0xd0 bpf_prog_report_arena_violation+0x90/0xb0 ex_handler_bpf+0x4a/0xa0 fixup_exception+0xde/0x310 kernelmode_fixup_or_oops.constprop.0+0x2f/0x70 exc_page_fault+0xdd/0x1d0 asm_exc_page_fault+0x26/0x30 bpf_prog_3699ea119d1f6ed8_foo+0x10c/0x140 *(u64 __arena *)0xfaceb00c = *(u64 __arena *)0xdeadbeef; @ stream_bpftool.c:68 bpf_prog_9b324ec4a1b2a5c0_stream_bpftool_dump_prog_stream+0x7e/0x2d0 foo(stream); @ stream_bpftool.c:93 bpf_prog_test_run_syscall+0x102/0x240 __sys_bpf+0xd68/0x2bf0 __x64_sys_bpf+0x1e/0x30 do_syscall_64+0x68/0x140 entry_SYSCALL_64_after_hwframe+0x76/0x7e ERROR: Arena WRITE access at unmapped address 0xfaceb00c CPU: 48 UID: 0 PID: 786 Comm: test_progs Call trace: bpf_stream_stage_dump_stack+0xb0/0xd0 bpf_prog_report_arena_violation+0x90/0xb0 ex_handler_bpf+0x4a/0xa0 fixup_exception+0xde/0x310 kernelmode_fixup_or_oops.constprop.0+0x2f/0x70 exc_page_fault+0xdd/0x1d0 asm_exc_page_fault+0x26/0x30 bpf_prog_3699ea119d1f6ed8_foo+0x111/0x140 *(u64 __arena *)0xfaceb00c = *(u64 __arena *)0xdeadbeef; @ stream_bpftool.c:68 bpf_prog_9b324ec4a1b2a5c0_stream_bpftool_dump_prog_stream+0x7e/0x2d0 foo(stream); @ stream_bpftool.c:93 bpf_prog_test_run_syscall+0x102/0x240 __sys_bpf+0xd68/0x2bf0 __x64_sys_bpf+0x1e/0x30 do_syscall_64+0x68/0x140 entry_SYSCALL_64_after_hwframe+0x76/0x7e ERROR: Timeout detected for may_goto instruction CPU: 48 UID: 0 PID: 786 Comm: test_progs Call trace: bpf_stream_stage_dump_stack+0xb0/0xd0 bpf_prog_report_may_goto_violation+0x6a/0x90 bpf_check_timed_may_goto+0x4d/0xa0 arch_bpf_timed_may_goto+0x21/0x40 bpf_prog_3699ea119d1f6ed8_foo+0x12f/0x140 while (can_loop) @ stream_bpftool.c:71 bpf_prog_9b324ec4a1b2a5c0_stream_bpftool_dump_prog_stream+0x7e/0x2d0 foo(stream); @ stream_bpftool.c:93 bpf_prog_test_run_syscall+0x102/0x240 __sys_bpf+0xd68/0x2bf0 __x64_sys_bpf+0x1e/0x30 do_syscall_64+0x68/0x140 entry_SYSCALL_64_after_hwframe+0x76/0x7e Changelog: ---------- RFC v1 -> v1 RFC v1: https://lore.kernel.org/bpf/20250414161443.1146103-1-memx... * Rebase on bpf-next/master. * Change output in dump_stack to also print source line. (Alexei) * Simplify API to single pop() operation. (Eduard, Alexei) * Add kdoc for bpf_dynptr_from_mem_slice. * Fix -EINVAL returned from prog_dump_stream. (Eduard) * Split dump_stack() patch into multiple commits. * Add macro wrapping stream staging API. * Change bpftool command from dump to tracelog. (Quentin) * Add bpftool documentation and bash completion. (Quentin) * Change license of bpftool to Dual BSD/GPL. * Simplify memory allocator (Alexei). * No overflow into second page. * Remove bpf_mem_alloc() fallback. * Symlink bpftool BPF program and exercise as selftest. (Eduard) * Verify output after dumping from ringbuf. (Eduard) * More failure cases to check API invariants. * Remove patches for dynptr lifetime fixes (split into separate set). * Limit maximum error messages, and add stream capacity (Eduard). Kumar Kartikeya Dwivedi (11): bpf: Introduce bpf_dynptr_from_mem_slice bpf: Introduce BPF standard streams bpf: Add function to extract program source info bpf: Add function to find program from stack trace bpf: Add dump_stack() analogue to print to BPF stderr bpf: Report may_goto timeout to BPF stderr bpf: Report rqspinlock deadlocks/timeout to BPF stderr bpf: Report arena faults to BPF stderr libbpf: Add bpf_stream_printk() macro bpftool: Add support for dumping streams selftests/bpf: Add tests for prog streams arch/x86/net/bpf_jit_comp.c | 22 +- include/linux/bpf.h | 91 ++- kernel/bpf/Makefile | 2 +- kernel/bpf/arena.c | 14 + kernel/bpf/core.c | 95 ++- kernel/bpf/helpers.c | 63 +- kernel/bpf/rqspinlock.c | 22 + kernel/bpf/stream.c | 552 ++++++++++++++++++ kernel/bpf/syscall.c | 2 +- kernel/bpf/verifier.c | 21 +- .../bpftool/Documentation/bpftool-prog.rst | 6 + tools/bpf/bpftool/Makefile | 2 +- tools/bpf/bpftool/bash-completion/bpftool | 16 +- tools/bpf/bpftool/prog.c | 88 ++- tools/bpf/bpftool/skeleton/stream.bpf.c | 69 +++ tools/lib/bpf/bpf_helpers.h | 44 +- .../testing/selftests/bpf/prog_tests/stream.c | 95 +++ tools/testing/selftests/bpf/progs/stream.c | 127 ++++ .../selftests/bpf/progs/stream_bpftool.c | 1 + .../testing/selftests/bpf/progs/stream_fail.c | 90 +++ 20 files changed, 1383 insertions(+), 39 deletions(-) create mode 100644 kernel/bpf/stream.c create mode 100644 tools/bpf/bpftool/skeleton/stream.bpf.c create mode 100644 tools/testing/selftests/bpf/prog_tests/stream.c create mode 100644 tools/testing/selftests/bpf/progs/stream.c create mode 120000 tools/testing/selftests/bpf/progs/stream_bpftool.c create mode 100644 tools/testing/selftests/bpf/progs/stream_fail.c base-commit: 43745d11bfd9683abdf08ad7a5cc403d6a9ffd15 -- 2.47.1