From: Eduard Zingerman <eddyz87@gmail.com>
To: Yonghong Song <yonghong.song@linux.dev>, bpf@vger.kernel.org
Cc: Alexei Starovoitov <ast@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
kernel-team@fb.com
Subject: Re: [PATCH bpf-next v2] bpf: Rewrite "rX <<= 32; rX >>= 32" into "wX = wX" to keep linked scalars
Date: Fri, 21 Aug 2026 10:36:06 -0700 [thread overview]
Message-ID: <f97bb12895dea33aa8f79b0468b5ada81510cc9d.camel@gmail.com> (raw)
In-Reply-To: <20260821042837.2786719-1-yonghong.song@linux.dev>
On Thu, 2026-08-20 at 21:28 -0700, Yonghong Song wrote:
> For the following test in
> tools/testing/selftests/bpf/progs/verifier_linked_scalars.c:
>
> void alu32_negative_offset(void)
> {
> volatile char path[5];
> volatile int offset = bpf_get_prandom_u32();
> int off = offset;
>
> if (off >= 5 && off < 10)
> path[off - 5] = '.';
>
> /* So compiler doesn't say: error: variable 'path' set but not used */
> __sink(path[0]);
> }
>
> Without alu32 (-mcpu=v2), the test
> verifier_linked_scalars/alu32_negative_offset will fail with llvm22 and
> llvm23 like below.
>
> 3: (bf) r2 = r1 ; R1=scalar(id=1,...) R2=scalar(id=1,...)
Does r1 fit into 32-bit range at this point?
I assume it does, otherwise it won't be possible to infer information
about r1 range through zero extended r2.
> 4: (07) r2 += -5 ; R2=scalar(id=1-5,smin=-5,smax=0xfffffffa)
> 5: (67) r2 <<= 32 ; R2=scalar(smax=0x7fffffff00000000,...)
> 6: (77) r2 >>= 32 ; R2=scalar(smin=0,umax=0xffffffff,...)
> 7: (25) if r2 > 0x4 goto pc+5 ; R2=scalar(smin=0,smax=umax=4,...)
> 8: (bf) r2 = r10
> 9: (07) r2 += -5
> 10: (0f) r2 += r1 ; R1=scalar(id=1,smin=0,umax=0xffffffff)
> ; R2=fp(smin=-5,smax=0xfffffffa)
> 11: (b7) r1 = 46 ; R1=46
> 12: (73) *(u8 *)(r2 -5) = r1
> invalid unbounded variable-offset write to stack R2
>
> R1 is never narrowed down, so the address stays unbounded and the store
> is rejected.
...
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 821b47ac75c5..e1de442801d9 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -15610,6 +15610,14 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
> return 0;
> }
>
> +static bool linked_base_fits_u32(const struct bpf_reg_state *reg)
> +{
> + if (reg->id & BPF_ADD_CONST32)
> + return true;
> + return reg_smin(reg) >= (s64)reg->delta &&
> + reg_smax(reg) <= (s64)U32_MAX + (s64)reg->delta;
> +}
> +
> /* Handles ALU ops other than BPF_END, BPF_NEG and BPF_MOV: computes new min/max
> * and var_off.
> */
> @@ -15878,7 +15886,12 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
> insn->src_reg);
> return -EACCES;
> } else if (src_reg->type == SCALAR_VALUE) {
> - if (insn->off == 0) {
> + if (insn->off == 0 && insn->src_reg == insn->dst_reg &&
> + (dst_reg->id & BPF_ADD_CONST) &&
> + linked_base_fits_u32(dst_reg)) {
> + dst_reg->id = (dst_reg->id & ~BPF_ADD_CONST64) |
> + BPF_ADD_CONST32;
This commit consists of two parts:
- a special case for wA = wA assignment
- a rewrite for `rA <<= 32; rA >>= 32;` pair
Could you please split it in two with separate selftest for each.
Also, could you please comment why the special case for `wA = wA` is necessary?
Is it because assign_scalar_id_before_mov() destroys the link:
static void assign_scalar_id_before_mov(struct bpf_verifier_env *env,
struct bpf_reg_state *src_reg)
...
if (src_reg->id & BPF_ADD_CONST)
clear_scalar_id(src_reg);
?
If that's the only reason, is it possible to extend existing wA = wB
logic instead of adding a special case?
Also note that this overlaps with Vineet's series [1].
Representing zero extension as a combination of BPF_ADD_CONST32 and
delta == 0 is a valid alternative for one of the patches there,
but it also handles the value reconstruction on sync.
[1] https://lore.kernel.org/bpf/20260814231945.3884596-1-vineet.gupta@linux.dev/
> + } else if (insn->off == 0) {
> bool is_src_reg_u32 = get_reg_width(src_reg) <= 32;
>
> if (is_src_reg_u32)
...
next prev parent reply other threads:[~2026-08-21 17:36 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-21 4:28 [PATCH bpf-next v2] bpf: Rewrite "rX <<= 32; rX >>= 32" into "wX = wX" to keep linked scalars Yonghong Song
2026-08-21 5:30 ` bot+bpf-ci
2026-08-21 17:36 ` Eduard Zingerman [this message]
2026-08-22 16:47 ` Yonghong Song
2026-08-24 18:29 ` Eduard Zingerman
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=f97bb12895dea33aa8f79b0468b5ada81510cc9d.camel@gmail.com \
--to=eddyz87@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=kernel-team@fb.com \
--cc=yonghong.song@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox