> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 5d0a2d3ef594..7ef324e384f4 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -11024,13 +11024,13 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
>
> /* reset caller saved regs */
> bpf_diag_record_caller_saved(env, regs);
> + bpf_diag_mod_begin(env, ®s[BPF_REG_0], NULL, BPF_DIAG_MOD_WRITE);
> for (i = 0; i < CALLER_SAVED_REGS; i++) {
> bpf_mark_reg_not_init(env, ®s[caller_saved[i]]);
> check_reg_arg(env, caller_saved[i], DST_OP_NO_MARK);
> }
> invalidate_outgoing_stack_args(env, cur_func(env));
>
> - bpf_diag_mod_begin(env, ®s[BPF_REG_0], NULL, BPF_DIAG_MOD_WRITE);
> /* update return register (already marked as written above) */
> ret_type = fn->ret_type;
> ret_flag = type_flag(ret_type);
Does this produce the correct diagnostic message for void helpers? The
new bpf_diag_mod_begin() is now opened unconditionally for all helpers,
including those with RET_VOID. Because the snapshot is taken before the
caller-saved clearing loop, a void helper now generates a history event
with R0's real pre-call value as old and NOT_INIT as new, with reason
BPF_DIAG_MOD_WRITE.
Looking at the return type handling:
switch (base_type(ret_type)) {
...
case RET_VOID:
regs[BPF_REG_0].type = NOT_INIT;
break;
...
bpf_diag_mod_end(env);
And the diagnostic rendering in diag_print_mod():
bpf_diag_source(env, event->insn_idx, label,
"%s changed from %s to %s", target_desc, old, new);
So a call to bpf_spin_lock(), bpf_spin_unlock(), bpf_ringbuf_submit(),
bpf_ringbuf_discard(), bpf_ringbuf_submit_dynptr(),
bpf_ringbuf_discard_dynptr() or bpf_tail_call() would now report
"update: R0 changed from <live value> to <invalid>", attributing the
loss of R0 to a value update by a helper that returns nothing, instead
of to the caller-saved clobber.
The correct rendering for caller-saved invalidation is one reason code
away: "R0: call invalidated this caller-saved register; previous value
was <live value>".
The commit message states the new ordering matches the kfunc, ld_abs,
and subprogram call paths, but check_func_call() explicitly
distinguishes the void case:
if (returns_void)
bpf_diag_record_scrub(env, &caller->regs[BPF_REG_0],
BPF_DIAG_MOD_CALLER_SAVED);
else
bpf_diag_mod_begin(env, &caller->regs[BPF_REG_0], NULL,
BPF_DIAG_MOD_WRITE);
clear_caller_saved_regs(env, caller->regs);
invalidate_outgoing_stack_args(env, cur_func(env));
Could check_helper_call() gate the bpf_diag_mod_begin() call the same
way using base_type(fn->ret_type) == RET_VOID? The impact is limited to
diagnostic text only - no bpf_reg_state, verifier decision, or
memory-safety behaviour changes - but the misattribution would be new.
---
> bpf: Preserve R0 lineage across helper calls
>
> check_helper_call() clears all caller-saved registers before taking the
> diagnostic snapshot of R0. This records NOT_INIT as the old state for every
> helper return and loses the lineage of the value held in R0 before the call.
> bpf_diag_record_caller_saved() deliberately skips R0 because the paired
> modification scope is responsible for it.
>
> Open the R0 modification scope before clearing caller-saved registers,
> matching the kfunc, ld_abs, and subprogram call paths.
>
> Reported-by: Sashiko <[email protected]>
> Link: https://lore.kernel.org/bpf/[email protected]/
> Link: https://lore.kernel.org/bpf/48e6f021b89562f68850fe21ef8c78719819b04cf9c4e4f50bc791937d37ace8@mail.kernel.org/
> Signed-off-by: Kumar Kartikeya Dwivedi <[email protected]>
This looks like a bug fix. Should this include:
Fixes: af4ea6e20fff ("bpf: Track verifier register diagnostic events")
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/31921026518
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.