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