Re: [PATCH bpf-next v4 08/13] bpf: Reject register-pair returns when the subprog BTF is unreliable
Yonghong Song <[email protected]>
| Newsgroups | org.kernel.vger.bpf |
|---|---|
| Message-ID | <[email protected]> |
On 8/12/26 3:24 PM, Eduard Zingerman wrote: > On Mon, 2026-08-10 at 17:09 -0700, Yonghong Song wrote: >> The R0:R2 return convention is derived from the BTF function prototype: >> bpf_compute_subprog_ret_regs() inspects the return type of every >> subprogram and records whether its value comes back in a register pair. >> >> btf_check_subprog_call() can decide, at a call site, that this BTF is >> not to be trusted and mark the subprogram unreliable, which happens when >> compiler optimizations remove arguments from a static function or when a >> mismatched type is passed to a global one. From that point on the >> verifier falls back to conservative, R0-only, semantics for the >> subprogram, while the compiled code keeps returning a pair and leaves >> the upper half in R2 behind the verifier's back. >> >> Rather than silently mistracking R2, reject a return value larger than >> 8 bytes as soon as the prototype it was derived from becomes unreliable. >> Add subprog_ret_pair_unreliable() and test it at the two places that can >> observe the flag: check_func_call(), for the call itself, and >> prepare_func_exit(), for the return from an inlined static subprogram. >> >> Note that the main program needs no such check: a >8 byte return from >> subprog 0 is rejected at BPF_EXIT regardless of whether its BTF is >> reliable. Callbacks need none either: a callback address only becomes a >> PTR_TO_FUNC through check_ld_imm(), which already rejects any callback >> returning more than 8 bytes. >> >> Signed-off-by: Yonghong Song <[email protected]> >> --- > I think this is a good example on why r0:r2 has to be inferred from > register liveness. The user has not real control over reliability of > BTF for static functions. Hence, this limitation might be quite > inconvenient in practice. > > Another option is to assume that static subprograms always return two > registers. Then if for some of them static liveness analysis shows > that second register is never used -- skip the register move in jit. > This latter option seem appealing to me, as it appears to simplify > the patch-set. For >= llvm23 we have true signatures so return types (registers) should match actual code. > > ...