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