From: sashiko-bot@kernel.org
Cc: bpf@vger.kernel.org
Subject: Re: [RFC PATCH 2/4] tracing/probes: Compile all fetchargs into a single BPF program per event
Date: Wed, 01 Jul 2026 14:06:30 +0000 [thread overview]
Message-ID: <20260701140630.8BA6E1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <178291354144.1566898.14374948740441958770.stgit@devnote2>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [Critical] Early termination of the BPF fetch program upon a single memory fault skips the processing of all subsequent probe arguments, exposing uninitialized ring-buffer memory to userspace.
- [Critical] The generated BPF program bypasses the verifier and leaves `stack_depth` as 0, causing JIT to omit stack allocation and leading to stack corruption during memory fetches.
- [Critical] Direct invocation of `copy_from_kernel_nofault` using `BPF_EMIT_CALL` violates kCFI and architecture calling conventions.
- [High] Failures from `bpf_prog_select_runtime` are silently ignored because the code checks `IS_ERR(prog)` instead of the `err` out-parameter.
- [High] Missing `refcnt` initialization of the manually allocated BPF program leads to a permanent memory leak.
--
commit fb399d3b83423ab453a35bd3c084a85256eaf7df
Author: Masami Hiramatsu (Google) <mhiramat@kernel.org>
tracing/probes: Compile all fetchargs into a single BPF program per event
This commit compiles trace probe arguments into a single BPF program to
reduce prologue and dispatching overhead. It supports basic BPF-compatible
arguments and falls back to the interpreter loop if non-BPF operations
are required.
> diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
> index 18c2121223440..0deb53c22ae39 100644
> --- a/kernel/trace/trace_probe.c
> +++ b/kernel/trace/trace_probe.c
[ ... ]
> +static void trace_probe_compile_bpf(struct trace_probe *tp)
> +{
[ ... ]
> + case FETCH_OP_DEREF:
> + /* Add offset: R3 = R0 + code->offset (src) */
> + insns[i++] = BPF_MOV64_REG(BPF_REG_2, BPF_REG_0);
> + if (code->offset)
> + insns[i++] = BPF_ALU64_IMM(BPF_ADD, BPF_REG_2,
> + code->offset);
> + /* R1 = dst (R10 - 8 on stack) */
> + insns[i++] = BPF_MOV64_REG(BPF_REG_1, BPF_REG_10);
> + insns[i++] = BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8);
[Severity: Critical]
Does this stack access corrupt the caller's stack frame?
Since this manually constructed BPF program bypasses the verifier,
prog->aux->stack_depth remains 0. Because the stack depth is 0, the JIT
compiler will not allocate a stack frame for the program. When the program
writes to R10 - 8, it might overwrite the caller's stack frame or
callee-saved registers, potentially leading to kernel panics.
> + /* R3 = size */
> + insns[i++] = BPF_MOV64_IMM(BPF_REG_3, sizeof(unsigned long));
> + /* Call copy_from_kernel_nofault(dst, src, size) */
> + insns[i++] = BPF_EMIT_CALL(copy_from_kernel_nofault);
[Severity: Critical]
Can this direct call to copy_from_kernel_nofault trigger a kCFI panic?
copy_from_kernel_nofault is a standard C function with a 3-argument
signature, but BPF_EMIT_CALL executes a BPF helper call which expects
to pass 5 arguments in 64-bit BPF registers. Under Control Flow Integrity,
invoking this through the interpreter's 5-argument function pointer might
cause a signature mismatch and panic the kernel. It could also break the
standard calling convention on 32-bit architectures.
> + /* if (R0 < 0) return R0; */
> + insns[i++] = BPF_JMP_IMM(BPF_JSGE, BPF_REG_0, 0, 1);
> + insns[i++] = BPF_EXIT_INSN();
[Severity: Critical]
If a memory fault occurs here and the program exits early, does it leave the
remaining trace event ring buffer fields uninitialized?
Since trace_event_buffer_reserve() leaves the ring buffer uninitialized,
terminating the BPF program immediately on a single fault without zeroing
the current field or processing subsequent arguments might expose stale
kernel memory from the stack or heap to userspace when the buffer is
subsequently committed.
> + /* R0 = *(unsigned long *)(R10 - 8) */
> + insns[i++] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8);
> + break;
[ ... ]
> + /* Epilogue: return R9 (0) */
> + insns[i++] = BPF_MOV64_REG(BPF_REG_0, BPF_REG_9);
> + insns[i++] = BPF_EXIT_INSN();
> +
> + prog = bpf_prog_alloc(bpf_prog_size(i), 0);
> + if (!prog)
> + goto out;
[Severity: High]
Is a prog->aux->refcnt initialization needed here?
bpf_prog_alloc() zero-initializes the bpf_prog_aux structure, leaving
refcnt as 0. When bpf_prog_put() is later called during cleanup,
atomic64_dec_and_test(0) will evaluate to false, which causes the
program memory to never be freed.
> +
> + prog->len = i;
> + memcpy(prog->insnsi, insns, prog->len * sizeof(struct bpf_insn));
> + prog->type = BPF_PROG_TYPE_KPROBE;
> +
> + prog = bpf_prog_select_runtime(prog, &err);
> + if (IS_ERR(prog))
> + goto out;
> + tp->prog = prog;
[Severity: High]
Does this error check properly handle failures from bpf_prog_select_runtime?
bpf_prog_select_runtime() does not return ERR_PTR on failure; instead, it
returns the program pointer and sets the out-parameter err to a negative
error code. Checking IS_ERR(prog) evaluates to false, which might cause
the error to be ignored. If JIT compilation fails and the interpreter is
unavailable, this leaves prog->bpf_func as NULL, leading to a NULL pointer
dereference later.
--
Sashiko AI review · https://sashiko.dev/#/patchset/178291352217.1566898.14481561093843379745.stgit@devnote2?part=2
next prev parent reply other threads:[~2026-07-01 14:06 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-01 13:45 [RFC PATCH 0/4] tracing/probes: Optimize fetcharg with BPF Masami Hiramatsu (Google)
2026-07-01 13:45 ` [RFC PATCH 1/4] tools/tracing: Add fetcharg performance micro-benchmark Masami Hiramatsu (Google)
2026-07-01 13:53 ` sashiko-bot
2026-07-01 13:45 ` [RFC PATCH 2/4] tracing/probes: Compile all fetchargs into a single BPF program per event Masami Hiramatsu (Google)
2026-07-01 14:06 ` sashiko-bot [this message]
2026-07-01 18:41 ` Alexei Starovoitov
2026-07-01 18:47 ` Steven Rostedt
2026-07-01 18:53 ` Alexei Starovoitov
2026-07-01 22:40 ` Masami Hiramatsu
2026-07-02 0:01 ` Alexei Starovoitov
2026-07-02 1:01 ` Masami Hiramatsu
2026-07-02 14:04 ` Steven Rostedt
2026-07-01 13:45 ` [RFC PATCH 3/4] tracing: Add disable_bpf trace option to ignore eBPF for fetchargs Masami Hiramatsu (Google)
2026-07-01 14:02 ` sashiko-bot
2026-07-01 13:46 ` [RFC PATCH 4/4] selftests/ftrace: Add a test for eBPF compiled fetchargs Masami Hiramatsu (Google)
2026-07-01 13:53 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260701140630.8BA6E1F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.