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 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.