summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@kernel.org>2026-10-27 19:03:02 +0000
committerAlexei Starovoitov <ast@kernel.org>2026-10-28 04:07:02 +0000
commit3f9924747c4422176346c34b5dff44ba8bca5180 (patch)
treefa8eed396acc1da51c5be96db1f0364fbc28efb3 /kernel
parent701edc66772b41474f691664efc179d0de840ed1 (diff)
bpf: Clear delta of a register that scalar evolution widens
After 'r3 = r8; r3 += 4' the verifier knows that r3 == r8 + 4. The two registers have the same id, and r3 keeps the difference in reg->delta. When the prog compares one of them with a constant, sync_linked_regs() calculates the range of the other register from the difference of the two deltas. At a loop head scalar evolution widens a register: it replaces the register with its range over all iterations. Then the register is not linked to other registers. scratch_widened_reg_id() clears reg->id, but it does not clear reg->delta. A subsequent copy of the register gets the stale delta. Then the range of the copy is incorrect by this delta. r3 = r8 r3 += 4 ; R3=scalar(id=1+4) 1: ; r3 is widened: no id, delta is still 4 r4 = r3 ; id=2 and delta 4 in both r4 += 1 ; R4=scalar(id=2+1) if r3 > 10 goto 3f ; R3 <= 10, R4 = R3 + 1 - 4 <= 7 if r4 <= 7 goto 2f ... ; not verified, r4 is up to 11 here The verifier does not verify code that can run. Use clear_scalar_id(). It clears id and delta together. Move it to bpf_verifier.h, so that scev.c can call it. Fixes: 6ccf49f79327 ("bpf: Use SCEV to widen bounded loops") Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://patch.msgid.link/20261027190314.1440199-8-alexei.starovoitov@gmail.com
Diffstat (limited to 'kernel')
-rw-r--r--kernel/bpf/scev.c2
-rw-r--r--kernel/bpf/verifier.c6
2 files changed, 1 insertions, 7 deletions
diff --git a/kernel/bpf/scev.c b/kernel/bpf/scev.c
index 04d4962448e2..3f7534cda47a 100644
--- a/kernel/bpf/scev.c
+++ b/kernel/bpf/scev.c
@@ -2391,7 +2391,7 @@ static void scratch_widened_reg_id(struct bpf_verifier_env *env, struct bpf_reg_
{
switch (base_type(reg->type)) {
case SCALAR_VALUE:
- reg->id = 0;
+ clear_scalar_id(reg);
break;
case PTR_TO_PACKET:
case PTR_TO_PACKET_META:
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index c1070aba621b..8139e41ace00 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -3824,12 +3824,6 @@ static bool __is_pointer_value(bool allow_ptr_leaks,
return is_pointer_regtype(reg->type);
}
-static void clear_scalar_id(struct bpf_reg_state *reg)
-{
- reg->id = 0;
- reg->delta = 0;
-}
-
static void assign_scalar_id_before_mov(struct bpf_verifier_env *env,
struct bpf_reg_state *src_reg)
{