From: sashiko-bot@kernel.org
To: "Eduard Zingerman" <eddyz87@gmail.com>, bpf@vger.kernel.org
Subject: Re: [PATCH bpf-next 1/2] bpf: support 32-bit linear scalar evolution
Date: Tue, 20 Oct 2026 11:38:54 +0000 [thread overview]
Message-ID: <sashiko-outbox-178898@kernel.org> (raw)
In-Reply-To: <20261020-scev-32bit-v1-1-838f34f9f0cd@gmail.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Critical] bpf: 32-bit linear SCEV corrupts pointer and scalar bounds
- [Critical] bpf: compute_max_iters() uses pointer offsets for 32-bit latches
- [Medium] bpf: bpf_clamp_scev_regs() misses empty r32 check on clamping
--
commit c93c9841341e0885c177c1612799cb18f92b0bfc
Author: Eduard Zingerman <eddyz87@gmail.com>
bpf: support 32-bit linear scalar evolution
This commit extends BPF scalar evolution (SCEV) analysis to represent and
compute iteration counts and widened bounds for 32-bit ALU recurrences and
32-bit conditional jumps. It also updates struct bounds and
bpf_set_reg_range() to track both 32-bit and 64-bit circular number ranges.
> diff --git a/kernel/bpf/scev.c b/kernel/bpf/scev.c
> index 48500d73105ac..fea77772ca967 100644
> --- a/kernel/bpf/scev.c
> +++ b/kernel/bpf/scev.c
[ ... ]
> @@ -2217,6 +2212,115 @@ static bool compute_max_iters(struct bpf_verifier_env *env,
> return false;
> }
>
> + *result = backedge_taken_count;
> + return true;
> +}
> +
> +/*
> + * Loop with post-condition:
> + *
> + * r0 = 0
> + * l: ... r0 ∈ [0,1,2] header executed 3 times
> + * r0 += 1 r0 ∈ [0,1,2]
> + * ... r0 ∈ [1,2,3]
> + * if r0 != 3 goto l r0 ∈ [1,2,3] backedge taken 2 times
> + * ... r0 ∈ [3]
> + *
> + * SCEV at header: r0 = k
> + * SCEV at latch: r0 = 1 + k
> + *
> + * Loop with pre-condition:
> + *
> + * r0 = 0
> + * l: ... r0 ∈ [0,1,2,3] header executed 4 times
> + * if r0 == 3 goto e r0 ∈ [0,1,2,3] backedge taken 3 times
> + * r0 += 1 r0 ∈ [0,1,2]
> + * ... r0 ∈ [1,2,3]
> + * goto l r0 ∈ [1,2,3]
> + * e: ... r0 ∈ [3]
> + *
> + * SCEV at header: r0 = k
> + * SCEV at latch: r0 = k
> + */
> +static bool compute_max_iters(struct bpf_verifier_env *env,
> + struct bpf_func_state *st,
> + struct linear_latch *latch,
> + struct bpf_loop_iters *iters)
> +{
> + struct bpf_insn_aux_data *aux = env->insn_aux_data;
> + struct bpf_loop *loop = aux[bpf_loop_at_index(env, latch->insn_idx)].loop;
> + struct scev *scev = env->scev;
> + struct scev_value initial_val, step_val, bound_val;
> + u64 step, bound, initial, total_change, backedge_taken_count;
> + u8 op = latch->op;
> +
> + if (!eval_expr(env, scev, st, latch->base_expr, &initial_val) ||
> + !eval_expr(env, scev, st, latch->step_expr, &step_val) ||
> + !eval_expr(env, scev, st, latch->bound_expr, &bound_val))
> + return false;
> +
> + if (step_val.ptr_reg >= 0) {
> + if (env->log.level & BPF_LOG_LEVEL2) {
> + bpf_log(&env->log, "scev: latch step is a pointer ");
> + log_scev_value(env, st, &step_val);
> + bpf_log(&env->log, "\n");
> + }
> + return false;
> + }
> + if (!scev_value_compatible(env, st, &initial_val, &bound_val))
> + return false;
> +
> + initial = initial_val.value;
> + step = step_val.value;
> + bound = bound_val.value;
> +
> + /*
> + * The code below only handles mixed 64-bit/32-bit comparisons/recurrences
> + * when initial bounds and step fit in 32-bit domain.
> + */
> + if (latch->zext32 || latch->jmp32) {
[Severity: Critical]
Should compute_max_iters() reject pointer operands (initial_val.ptr_reg >= 0
or bound_val.ptr_reg >= 0) when latch->zext32 or latch->jmp32 is true?
When eval_expr() evaluates a constant-offset pointer register, it sets
result->value to reg->var_off.value (the offset relative to the runtime base
address) and result->ptr_reg >= 0. If two registers r1 and r2 point to the
same memory object (for example, PTR_TO_PACKET, PTR_TO_MAP_VALUE, or
PTR_TO_STACK with r1 = base + 0 and r2 = base + 9), scev_value_compatible()
succeeds.
While comparing relative offsets works for 64-bit jumps and 64-bit pointer
arithmetic because valid kernel objects do not cross 64-bit address space
boundaries, a BPF_JMP32 latch (such as "if w1 < w2 goto l" with "r1 += 2")
compares the low 32 bits of the runtime kernel addresses: (u32)(base + offset)
or (s32)(base + offset).
Because (u32)base is unknown at verification time and can sit near U32_MAX or
S32_MAX, (u32)(base + initial + k * step) and (u32)(base + bound) can wrap
around U32_MAX -> 0 or S32_MAX -> S32_MIN at runtime even when the relative
offsets initial, bound, and total_change are small (e.g. if (u32)base ==
0xfffffff6, then w2 == 0xffffffff and w1 wraps around U32_MAX on even values
without terminating). Can this cause compute_max_iters() to compute an
unsound max_header_count and widen pointer or scalar induction variables to
incorrect bounds?
> + /*
> + * With the above constraint doing `l: w0 += 1; if r0 s< 256 goto l;`
> + * is equivalent to `l: w0 += 1; if r0 < 256 goto l;`
> + */
> + if (latch->jmp32 && is_signed_op(op)) {
> + initial = (s64)(s32)(u32)initial;
> + bound = (s64)(s32)(u32)bound;
> + step = (s64)(s32)(u32)step;
> + } else {
> + initial = (u32)initial;
> + bound = (u32)bound;
> + step = (s64)(s32)(u32)step;
> + }
> + }
[ ... ]
> @@ -2542,8 +2699,7 @@ int bpf_compute_loop_iters(struct bpf_verifier_env *env, struct bpf_verifier_sta
> r_scev = header_env->reg2scev[r];
> reg = scev_reg_for_linear(cur_func, r);
> /* If SCEV for r is (linear <reg> <slope>) */
> - if (is_simple_linear(scev, r_scev, &base_reg, &slope_imm) &&
> - reg && is_widenable_reg_type(reg)) {
> + if (reg && is_simple_linear(scev, r_scev, &coefs) && is_widenable_reg_type(reg)) {
[Severity: Critical]
Can allowing coefs.zext32 on non-scalar registers corrupt pointer and scalar
bounds during widening and clamping?
In bpf_compute_loop_iters(), is_widenable_reg_type(reg) accepts pointer types
such as PTR_TO_MAP_VALUE, PTR_TO_STACK, and PTR_TO_PACKET alongside
SCALAR_VALUE, even when is_simple_linear() sets coefs.zext32 = true (for
example, when a loop body executes "w7 += 8" on a register r7 holding a
pointer at loop entry).
This leads to two issues:
1. At loop entry, bpf_widen_scev_regs() calls linear_bounds() with
coefs.zext32 = true on the pointer's relative offset while keeping reg->type
as a pointer. For negative pointer offsets such as fp-64, cnum64_zext32()
zero-extends the 32-bit offset to 0xffffffc0.. and unions it into reg->r64 on
a PTR_TO_STACK register. For PTR_TO_MAP_VALUE at offset 0 (with 4 header
visits and step 8), bpf_widen_scev_regs() widens r7 at the header to
PTR_TO_MAP_VALUE with offset [0, 24].
2. When do_check() verifies "w7 += 8" in the loop body with
env->allow_ptr_leaks enabled, adjust_ptr_min_max_vals() rejects 32-bit
pointer arithmetic via mark_reg_unknown() and scalar32_min_max_add(), turning
r7 in cur_func_state into an unknown SCALAR_VALUE holding the low 32 bits of
the runtime kernel pointer plus 8. When execution reaches the loop header
along the backedge, bpf_clamp_scev_regs() computes linear_bounds() from
entry_reg (which is still PTR_TO_MAP_VALUE with offset 0, yielding bounds
[0, 24]) and intersects those pointer-offset bounds directly into reg (which
is now SCALAR_VALUE) without checking that entry_reg and reg are scalars or
have matching types. The verifier then treats scalar r7 as bounded to [0, 24]
while at runtime it holds (u32)map_value_kaddr + 8.
Should zext32 linear SCEVs be restricted to reg->type == SCALAR_VALUE (and
should bpf_clamp_scev_regs() verify that entry_reg and reg have compatible
types)?
> /* Spills at varying offsets lose precision */
> if (test_bit(r, loop->store_base_regs)) {
> spill_base = true;
[ ... ]
> @@ -2737,9 +2891,10 @@ int bpf_clamp_scev_regs(struct bpf_verifier_env *env, struct bpf_func_state *cur
> is_unbound_scev_reg(env, entry_st, r))
> continue;
>
> - linear_bounds(entry_reg, max_header_count, slope_imm, &bounds);
> - bounds.range = cnum64_intersect(reg->r64, bounds.range);
> - if (cnum64_is_empty(bounds.range)) {
> + linear_bounds(entry_reg, max_header_count, &coefs, &bounds);
> + bounds.r64 = cnum64_intersect(reg->r64, bounds.r64);
> + bounds.r32 = cnum32_intersect(reg->r32, bounds.r32);
> + if (cnum64_is_empty(bounds.r64)) {
> verifier_bug(env, "scev clamp produced empty range for r%d", r);
> return -EFAULT;
> }
[Severity: Medium]
Can bpf_clamp_scev_regs() pass an empty bounds.r32 to bpf_set_reg_range() and
trigger a register invariants violation in reg_bounds_sanity_check()?
In linear_bounds(), when coefs->zext32 is true and the 32-bit range wraps
around 0 and U32_MAX (e.g. w1 = 0 at entry, step = -1, two header visits),
bounds.r64 becomes [0, U32_MAX] while bounds.r32 is [-1, 0] (similarly, if
entry_reg has non-zero upper 32 bits, bounds.r64 is wider than bounds.r32).
If an in-loop branch refines reg on the backedge to a 32-bit value outside
bounds.r32 (for example, w1 == -2, so reg->r64 is [0xfffffffe, 0xfffffffe]
and reg->r32 is [-2, -2]), intersecting reg->r64 with [0, U32_MAX] produces a
non-empty bounds.r64, whereas intersecting reg->r32 with [-1, 0] produces
CNUM32_EMPTY. (A similar situation can occur when !coefs->zext32 leaves
bounds.r32 as CNUM32_UNBOUNDED, and deduce_bounds_32_from_64() inside
reg_bounds_sync() intersects reg->r32 with the 32-bit projection of
bounds.r64.)
Because bpf_clamp_scev_regs() only checks cnum64_is_empty(bounds.r64), it
proceeds to bpf_set_reg_range(), where reg_bounds_sanity_check() flags
cnum32_is_empty(reg->r32) as a range bounds violation. Should
bpf_clamp_scev_regs() also check cnum32_is_empty(bounds.r32)?
> @@ -2747,13 +2902,12 @@ int bpf_clamp_scev_regs(struct bpf_verifier_env *env, struct bpf_func_state *cur
> bpf_log(log, "loop header at %d, clamping ", insn_idx);
> log_reg(env, r);
> bpf_log(log, " to ");
> - bpf_verbose_snum(env, cnum64_smin(bounds.range));
> - bpf_log(log, "..");
> - bpf_verbose_snum(env, cnum64_smax(bounds.range));
> - bpf_log(log, " step %u\n", bounds.step);
> + log_bounds(env, &bounds);
> + bpf_log(log, "\n");
> }
> scratch_widened_reg_id(env, reg);
> - err = bpf_set_reg_range(env, reg, bounds.range, bounds.base, bounds.step);
> + err = bpf_set_reg_range(env, reg, bounds.r64, bounds.r32,
> + bounds.base, bounds.step);
> if (err)
> return err;
> mark_scev_reg_scratched(env, r);
[ ... ]
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index d138688468236..ea26da040ff96 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -17587,10 +17587,10 @@ bool bpf_same_memory_origin(const struct bpf_reg_state *reg_a,
> }
>
> int bpf_set_reg_range(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
> - struct cnum64 range, u16 base, u16 step)
> + struct cnum64 r64, struct cnum32 r32, u16 base, u16 step)
> {
> - reg->r64 = range;
> - reg->r32 = CNUM32_UNBOUNDED;
> + reg->r64 = r64;
> + reg->r32 = r32;
> reg->step = step;
> reg->base = base;
> reg->var_off = tnum_unknown;
[ ... ]
完美
Let me double-check that I didn't accidentally output any trailing characters or markdown. Wait—I have not output the final response yet! Let's output the clean plain-text report now, ending with a blank line.commit c93c9841341e0885c177c1612799cb18f92b0bfc
Author: Eduard Zingerman <eddyz87@gmail.com>
bpf: support 32-bit linear scalar evolution
This commit extends BPF scalar evolution (SCEV) analysis to represent and
compute iteration counts and widened bounds for 32-bit ALU recurrences and
32-bit conditional jumps. It also updates struct bounds and
bpf_set_reg_range() to track both 32-bit and 64-bit circular number ranges.
> diff --git a/kernel/bpf/scev.c b/kernel/bpf/scev.c
> index 48500d73105ac..fea77772ca967 100644
> --- a/kernel/bpf/scev.c
> +++ b/kernel/bpf/scev.c
[ ... ]
> @@ -2217,6 +2212,115 @@ static bool compute_max_iters(struct bpf_verifier_env *env,
> return false;
> }
>
> + *result = backedge_taken_count;
> + return true;
> +}
> +
> +/*
> + * Loop with post-condition:
> + *
> + * r0 = 0
> + * l: ... r0 ∈ [0,1,2] header executed 3 times
> + * r0 += 1 r0 ∈ [0,1,2]
> + * ... r0 ∈ [1,2,3]
> + * if r0 != 3 goto l r0 ∈ [1,2,3] backedge taken 2 times
> + * ... r0 ∈ [3]
> + *
> + * SCEV at header: r0 = k
> + * SCEV at latch: r0 = 1 + k
> + *
> + * Loop with pre-condition:
> + *
> + * r0 = 0
> + * l: ... r0 ∈ [0,1,2,3] header executed 4 times
> + * if r0 == 3 goto e r0 ∈ [0,1,2,3] backedge taken 3 times
> + * r0 += 1 r0 ∈ [0,1,2]
> + * ... r0 ∈ [1,2,3]
> + * goto l r0 ∈ [1,2,3]
> + * e: ... r0 ∈ [3]
> + *
> + * SCEV at header: r0 = k
> + * SCEV at latch: r0 = k
> + */
> +static bool compute_max_iters(struct bpf_verifier_env *env,
> + struct bpf_func_state *st,
> + struct linear_latch *latch,
> + struct bpf_loop_iters *iters)
> +{
> + struct bpf_insn_aux_data *aux = env->insn_aux_data;
> + struct bpf_loop *loop = aux[bpf_loop_at_index(env, latch->insn_idx)].loop;
> + struct scev *scev = env->scev;
> + struct scev_value initial_val, step_val, bound_val;
> + u64 step, bound, initial, total_change, backedge_taken_count;
> + u8 op = latch->op;
> +
> + if (!eval_expr(env, scev, st, latch->base_expr, &initial_val) ||
> + !eval_expr(env, scev, st, latch->step_expr, &step_val) ||
> + !eval_expr(env, scev, st, latch->bound_expr, &bound_val))
> + return false;
> +
> + if (step_val.ptr_reg >= 0) {
> + if (env->log.level & BPF_LOG_LEVEL2) {
> + bpf_log(&env->log, "scev: latch step is a pointer ");
> + log_scev_value(env, st, &step_val);
> + bpf_log(&env->log, "\n");
> + }
> + return false;
> + }
> + if (!scev_value_compatible(env, st, &initial_val, &bound_val))
> + return false;
> +
> + initial = initial_val.value;
> + step = step_val.value;
> + bound = bound_val.value;
> +
> + /*
> + * The code below only handles mixed 64-bit/32-bit comparisons/recurrences
> + * when initial bounds and step fit in 32-bit domain.
> + */
> + if (latch->zext32 || latch->jmp32) {
[Severity: Critical]
Should compute_max_iters() reject pointer operands (initial_val.ptr_reg >= 0
or bound_val.ptr_reg >= 0) when latch->zext32 or latch->jmp32 is true?
When eval_expr() evaluates a constant-offset pointer register, it sets
result->value to reg->var_off.value (the offset relative to the runtime base
address) and result->ptr_reg >= 0. If two registers r1 and r2 point to the
same memory object (for example, PTR_TO_PACKET, PTR_TO_MAP_VALUE, or
PTR_TO_STACK with r1 = base + 0 and r2 = base + 9), scev_value_compatible()
succeeds.
While comparing relative offsets works for 64-bit jumps and 64-bit pointer
arithmetic because valid kernel objects do not cross 64-bit address space
boundaries, a BPF_JMP32 latch (such as "if w1 < w2 goto l" with "r1 += 2")
compares the low 32 bits of the runtime kernel addresses: (u32)(base + offset)
or (s32)(base + offset).
Because (u32)base is unknown at verification time and can sit near U32_MAX or
S32_MAX, (u32)(base + initial + k * step) and (u32)(base + bound) can wrap
around U32_MAX -> 0 or S32_MAX -> S32_MIN at runtime even when the relative
offsets initial, bound, and total_change are small (e.g. if (u32)base ==
0xfffffff6, then w2 == 0xffffffff and w1 wraps around U32_MAX on even values
without terminating). Can this cause compute_max_iters() to compute an
unsound max_header_count and widen pointer or scalar induction variables to
incorrect bounds?
> + /*
> + * With the above constraint doing `l: w0 += 1; if r0 s< 256 goto l;`
> + * is equivalent to `l: w0 += 1; if r0 < 256 goto l;`
> + */
> + if (latch->jmp32 && is_signed_op(op)) {
> + initial = (s64)(s32)(u32)initial;
> + bound = (s64)(s32)(u32)bound;
> + step = (s64)(s32)(u32)step;
> + } else {
> + initial = (u32)initial;
> + bound = (u32)bound;
> + step = (s64)(s32)(u32)step;
> + }
> + }
[ ... ]
> @@ -2542,8 +2699,7 @@ int bpf_compute_loop_iters(struct bpf_verifier_env *env, struct bpf_verifier_sta
> r_scev = header_env->reg2scev[r];
> reg = scev_reg_for_linear(cur_func, r);
> /* If SCEV for r is (linear <reg> <slope>) */
> - if (is_simple_linear(scev, r_scev, &base_reg, &slope_imm) &&
> - reg && is_widenable_reg_type(reg)) {
> + if (reg && is_simple_linear(scev, r_scev, &coefs) && is_widenable_reg_type(reg)) {
[Severity: Critical]
Can allowing coefs.zext32 on non-scalar registers corrupt pointer and scalar
bounds during widening and clamping?
In bpf_compute_loop_iters(), is_widenable_reg_type(reg) accepts pointer types
such as PTR_TO_MAP_VALUE, PTR_TO_STACK, and PTR_TO_PACKET alongside
SCALAR_VALUE, even when is_simple_linear() sets coefs.zext32 = true (for
example, when a loop body executes "w7 += 8" on a register r7 holding a
pointer at loop entry).
This leads to two issues:
1. At loop entry, bpf_widen_scev_regs() calls linear_bounds() with
coefs.zext32 = true on the pointer's relative offset while keeping reg->type
as a pointer. For negative pointer offsets such as fp-64, cnum64_zext32()
zero-extends the 32-bit offset to 0xffffffc0.. and unions it into reg->r64 on
a PTR_TO_STACK register. For PTR_TO_MAP_VALUE at offset 0 (with 4 header
visits and step 8), bpf_widen_scev_regs() widens r7 at the header to
PTR_TO_MAP_VALUE with offset [0, 24].
2. When do_check() verifies "w7 += 8" in the loop body with
env->allow_ptr_leaks enabled, adjust_ptr_min_max_vals() rejects 32-bit
pointer arithmetic via mark_reg_unknown() and scalar32_min_max_add(), turning
r7 in cur_func_state into an unknown SCALAR_VALUE holding the low 32 bits of
the runtime kernel pointer plus 8. When execution reaches the loop header
along the backedge, bpf_clamp_scev_regs() computes linear_bounds() from
entry_reg (which is still PTR_TO_MAP_VALUE with offset 0, yielding bounds
[0, 24]) and intersects those pointer-offset bounds directly into reg (which
is now SCALAR_VALUE) without checking that entry_reg and reg are scalars or
have matching types. The verifier then treats scalar r7 as bounded to [0, 24]
while at runtime it holds (u32)map_value_kaddr + 8.
Should zext32 linear SCEVs be restricted to reg->type == SCALAR_VALUE (and
should bpf_clamp_scev_regs() verify that entry_reg and reg have compatible
types)?
> /* Spills at varying offsets lose precision */
> if (test_bit(r, loop->store_base_regs)) {
> spill_base = true;
[ ... ]
> @@ -2737,9 +2891,10 @@ int bpf_clamp_scev_regs(struct bpf_verifier_env *env, struct bpf_func_state *cur
> is_unbound_scev_reg(env, entry_st, r))
> continue;
>
> - linear_bounds(entry_reg, max_header_count, slope_imm, &bounds);
> - bounds.range = cnum64_intersect(reg->r64, bounds.range);
> - if (cnum64_is_empty(bounds.range)) {
> + linear_bounds(entry_reg, max_header_count, &coefs, &bounds);
> + bounds.r64 = cnum64_intersect(reg->r64, bounds.r64);
> + bounds.r32 = cnum32_intersect(reg->r32, bounds.r32);
> + if (cnum64_is_empty(bounds.r64)) {
> verifier_bug(env, "scev clamp produced empty range for r%d", r);
> return -EFAULT;
> }
[Severity: Medium]
Can bpf_clamp_scev_regs() pass an empty bounds.r32 to bpf_set_reg_range() and
trigger a register invariants violation in reg_bounds_sanity_check()?
In linear_bounds(), when coefs->zext32 is true and the 32-bit range wraps
around 0 and U32_MAX (e.g. w1 = 0 at entry, step = -1, two header visits),
bounds.r64 becomes [0, U32_MAX] while bounds.r32 is [-1, 0] (similarly, if
entry_reg has non-zero upper 32 bits, bounds.r64 is wider than bounds.r32).
If an in-loop branch refines reg on the backedge to a 32-bit value outside
bounds.r32 (for example, w1 == -2, so reg->r64 is [0xfffffffe, 0xfffffffe]
and reg->r32 is [-2, -2]), intersecting reg->r64 with [0, U32_MAX] produces a
non-empty bounds.r64, whereas intersecting reg->r32 with [-1, 0] produces
CNUM32_EMPTY. (A similar situation can occur when !coefs->zext32 leaves
bounds.r32 as CNUM32_UNBOUNDED, and deduce_bounds_32_from_64() inside
reg_bounds_sync() intersects reg->r32 with the 32-bit projection of
bounds.r64.)
Because bpf_clamp_scev_regs() only checks cnum64_is_empty(bounds.r64), it
proceeds to bpf_set_reg_range(), where reg_bounds_sanity_check() flags
cnum32_is_empty(reg->r32) as a range bounds violation. Should
bpf_clamp_scev_regs() also check cnum32_is_empty(bounds.r32)?
> @@ -2747,13 +2902,12 @@ int bpf_clamp_scev_regs(struct bpf_verifier_env *env, struct bpf_func_state *cur
> bpf_log(log, "loop header at %d, clamping ", insn_idx);
> log_reg(env, r);
> bpf_log(log, " to ");
> - bpf_verbose_snum(env, cnum64_smin(bounds.range));
> - bpf_log(log, "..");
> - bpf_verbose_snum(env, cnum64_smax(bounds.range));
> - bpf_log(log, " step %u\n", bounds.step);
> + log_bounds(env, &bounds);
> + bpf_log(log, "\n");
> }
> scratch_widened_reg_id(env, reg);
> - err = bpf_set_reg_range(env, reg, bounds.range, bounds.base, bounds.step);
> + err = bpf_set_reg_range(env, reg, bounds.r64, bounds.r32,
> + bounds.base, bounds.step);
> if (err)
> return err;
> mark_scev_reg_scratched(env, r);
[ ... ]
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index d138688468236..ea26da040ff96 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -17587,10 +17587,10 @@ bool bpf_same_memory_origin(const struct bpf_reg_state *reg_a,
> }
>
> int bpf_set_reg_range(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
> - struct cnum64 range, u16 base, u16 step)
> + struct cnum64 r64, struct cnum32 r32, u16 base, u16 step)
> {
> - reg->r64 = range;
> - reg->r32 = CNUM32_UNBOUNDED;
> + reg->r64 = r64;
> + reg->r32 = r32;
> reg->step = step;
> reg->base = base;
> reg->var_off = tnum_unknown;
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020-scev-32bit-v1-0-838f34f9f0cd@gmail.com?part=1
next prev parent reply other threads:[~2026-10-20 11:38 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-20 11:06 [PATCH bpf-next 0/2] bpf: support 32-bit linear scalar evolution Eduard Zingerman
2026-10-20 11:06 ` [PATCH bpf-next 1/2] " Eduard Zingerman
2026-10-20 11:35 ` bot+bpf-ci
2026-10-20 21:00 ` Alexei Starovoitov
2026-10-20 21:06 ` Eduard Zingerman
2026-10-20 11:38 ` sashiko-bot [this message]
2026-10-20 11:06 ` [PATCH bpf-next 2/2] selftests/bpf: tests for 32-bit scalar evolution bounds computation Eduard Zingerman
2026-10-20 11:35 ` bot+bpf-ci
2026-10-20 21:00 ` [PATCH bpf-next 0/2] bpf: support 32-bit linear scalar evolution patchwork-bot+netdevbpf
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-178898@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=eddyz87@gmail.com \
--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