From: sashiko-bot@kernel.org
To: "Alexei Starovoitov" <alexei.starovoitov@gmail.com>, bpf@vger.kernel.org
Subject: Re: [PATCH bpf-next v2 16/29] bpf: Recompute a pointer after the jump that bounds its index
Date: Wed, 11 Nov 2026 05:48:10 +0000 [thread overview]
Message-ID: <sashiko-outbox-208365@kernel.org> (raw)
In-Reply-To: <20261111051341.2800252-17-alexei.starovoitov@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [High] bpf: missing BPF_MAX_VAR_OFF offset bounds check in
recompute_ptr()
--
commit 5f6f31940968145851bf6579a0206e69bee69836
Author: Alexei Starovoitov <ast@kernel.org>
bpf: Recompute a pointer after the jump that bounds its index
This commit extends linked-register refinement at conditional jumps to
recompute a pointer register p = x + i once a conditional jump bounds the
index i.
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 138581a759bbb..c2a3f74d441fe 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -19741,6 +19741,43 @@ static struct bpf_reg_state *scev_reg_for_fill(struct bpf_func_state *frame, u32
> return &ss->spilled_ptr;
> }
>
> +/*
> + * p = buf + i; if (i > 100) return 0; *p = 0;
> + * p is @dst_reg, x is @ptr_reg, i is @off_reg. Scalar evolution says that p == x + i. So the insns
> + * 'p = x; p += i' are a no-op at run time, and a state that is sound before them is sound after
> + * them: apply their transfer function. Type, object and offset of p are taken from x as it is now;
> + * how p was computed does not matter.
> + * The old p is replaced, not intersected: a state does not distinguish two values of one hash map,
> + * and the intersection of an offset into the one with an offset into the other holds for neither.
> + * It is replaced only if the new range is a subset of the old one. An empty range is a subset too:
> + * the path is infeasible, p is left as it is.
> + */
> +static bool recompute_ptr(struct bpf_verifier_env *env, struct bpf_reg_state *dst_reg,
> + const struct bpf_reg_state *ptr_reg, const struct bpf_reg_state *off_reg)
> +{
> + struct bpf_reg_state sum = *ptr_reg;
> +
> + /* the cpu can speculate past the jump with an out-of-bounds index */
> + if (!env->bypass_spec_v1)
> + return false;
> + /* 'p += i' assigns a new id to a packet pointer */
> + if (ptr_reg->type == SCALAR_VALUE || type_is_pkt_pointer(ptr_reg->type) ||
> + !bpf_is_widenable_reg_type(ptr_reg))
> + return false;
> + __mark_reg32_unbounded(&sum);
> + scalar_step_add(&sum, ptr_reg, off_reg);
> + sum.r64 = cnum64_add(ptr_reg->r64, off_reg->r64);
> + sum.var_off = tnum_add(ptr_reg->var_off, off_reg->var_off);
> + reg_bounds_sync(&sum);
> + if (reg_is_empty(&sum) || const_tnum_range_mismatch(&sum) ||
> + const_tnum_range_mismatch_32(&sum))
> + return false;
> + if (!bpf_reg_union_compatible(dst_reg, &sum) || !cnum64_is_subset(dst_reg->r64, sum.r64))
> + return false;
> + *dst_reg = sum;
> + return true;
> +}
[Severity: High]
Can recompute_ptr() overwrite *dst_reg with a pointer offset outside
(-BPF_MAX_VAR_OFF, BPF_MAX_VAR_OFF)?
When adjust_ptr_min_max_vals() verifies the earlier p = x + i while i is
not yet constant, check_reg_sane_offset_scalar() and
check_reg_sane_offset_ptr() only check known constant offsets and smin,
so dst_reg->r64 can have an smax >= BPF_MAX_VAR_OFF (for example
[-16, 0xfffffff0ULL] on PTR_TO_STACK). If a subsequent conditional jump
narrows i to the constant 0xfffffff0ULL, cnum64_is_subset(dst_reg->r64,
sum.r64) succeeds and recompute_ptr() sets dst_reg->var_off.value to
0xfffffff0ULL without calling check_reg_sane_offset_scalar() or
check_reg_sane_offset_ptr().
Downstream callers that assume a constant var_off.value fits in 32 bits
then truncate it, allowing out-of-bounds kernel memory access at runtime:
kernel/bpf/verifier.c:stack_slot_obj_get_spi() {
...
off = reg->var_off.value;
if (off >= 0 || off % BPF_REG_SIZE) {
...
}
Here 0xfffffff0ULL is truncated to int off = -16, validating stack slot
fp-16 while passing r10 + 0xfffffff0ULL to the helper or kfunc.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261111051341.2800252-1-alexei.starovoitov@gmail.com?part=16
next prev parent reply other threads:[~2026-11-11 5:48 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-11 5:13 [PATCH bpf-next v2 00/29] bpf: Find linked registers by scalar evolution, remove scalar ids Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 01/29] bpf: Keep the 32-bit range across a no-op sign extension Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 02/29] bpf: Model 32-bit shifts and divisions exactly in scalar evolution Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 03/29] bpf: Construct scalar evolution expressions without allocations Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 04/29] bpf: Don't join dead registers in scalar evolution Alexei Starovoitov
2026-11-11 8:27 ` bot+bpf-ci
2026-11-11 5:13 ` [PATCH bpf-next v2 05/29] bpf: Simplify scalar evolution expressions at construction Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 06/29] bpf: Give SSA names to the values that scalar evolution does not track Alexei Starovoitov
2026-11-11 8:27 ` bot+bpf-ci
2026-11-11 5:13 ` [PATCH bpf-next v2 07/29] bpf: Compute scalar evolution expressions for whole subprogs Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 08/29] bpf: Mark the attr argument of bpf_sys_bpf() as MEM_WRITE Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 09/29] bpf: Include older frames in a fill through an imprecise stack pointer Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 10/29] bpf: Detect a dead branch when a range and var_off don't overlap Alexei Starovoitov
2026-11-11 8:27 ` bot+bpf-ci
2026-11-11 5:13 ` [PATCH bpf-next v2 11/29] bpf: Don't treat half of a 64-bit spill as a 32-bit spill on big endian Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 12/29] bpf: Refine registers linked by scalar evolution at conditional jumps Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 13/29] bpf: Value number the phis of scalar evolution Alexei Starovoitov
2026-11-11 8:27 ` bot+bpf-ci
2026-11-11 5:13 ` [PATCH bpf-next v2 14/29] selftests/bpf: Test registers linked by " Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 15/29] selftests/bpf: Test sign extensions of a range and of a linked register Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 16/29] bpf: Recompute a pointer after the jump that bounds its index Alexei Starovoitov
2026-11-11 5:48 ` sashiko-bot [this message]
2026-11-11 5:13 ` [PATCH bpf-next v2 17/29] selftests/bpf: Test a pointer computed before its index is bounded Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 18/29] bpf: Promote memory behind a pointer to SCEV registers Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 19/29] selftests/bpf: Test the memory of a caller that a jump tests Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 20/29] bpf: Find a copy of an induction variable without scalar ids Alexei Starovoitov
2026-11-11 5:57 ` sashiko-bot
2026-11-11 5:13 ` [PATCH bpf-next v2 21/29] bpf: Compute scalar evolution expressions in irreducible loops Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 22/29] bpf: Remove sync_linked_regs(), refine by scalar evolution only Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 23/29] bpf: Recognize copies of a scalar by their ranges in flow_join_makes_up() Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 24/29] bpf: Stop assigning ids to scalars Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 25/29] bpf: Remove scalar ids from regsafe() Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 26/29] bpf: Remove scalar ids from the join of states Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 27/29] bpf: Remove scalar ids from the log and from bpf_verifier.h Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 28/29] bpf: Support sign-extended 32-bit linear scalar evolution Alexei Starovoitov
2026-11-11 5:13 ` [PATCH bpf-next v2 29/29] selftests/bpf: Test loops with a sign-extended 32-bit induction variable Alexei Starovoitov
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=sashiko-outbox-208365@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=alexei.starovoitov@gmail.com \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox