[PATCH stable 6.6.y v2 2/3] bpf: make the verifier tracks the "not equal" for regs
From: Zhenzhong Wu <hidden>
Date: 2026-06-07 17:10:24
Also in:
bpf, lkml, stable
Subsystem:
bpf [core], bpf [general] (safe dynamic programs and tools), the rest · Maintainers:
Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi, Linus Torvalds
From: Menglong Dong <redacted> [ Upstream commit d028f87517d6775dccff4ddbca2740826f9e53f1 ] We can derive useful information for BPF_JNE when one side is a constant and the constant is exactly at the edge of the other register range. For example, a > 0 can be compiled as a jump if a == 0. The equal branch marks the register as known zero, but the fallthrough branch also needs to preserve that the register is not zero. Without this, the range can remain [0, max] and later verifier state pruning can keep an impossible scalar path. The upstream fix lives in regs_refine_cond_op(). The 6.6.y verifier still uses the older reg_set_min_max() layout, so express the same branch-edge refinement there: for BPF_JEQ, preserve the known-equal true branch and exclude the constant from false_reg; for BPF_JNE, preserve the known-equal false branch and exclude the constant from true_reg. Signed-off-by: Menglong Dong <redacted> Acked-by: Andrii Nakryiko <andrii@kernel.org> Acked-by: Shung-Hsi Yu <redacted> Link: https://lore.kernel.org/r/20231219134800.1550388-2-menglong8.dong@gmail.com (local) Signed-off-by: Alexei Starovoitov <ast@kernel.org> [ zhenzhong: backport to 6.6.y reg_set_min_max() layout. ] Signed-off-by: Zhenzhong Wu <redacted> --- kernel/bpf/verifier.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 5f94bff12..de4f46796 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c@@ -14169,18 +14169,50 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg, if (is_jmp32) { __mark_reg32_known(true_reg, val32); true_32off = tnum_subreg(true_reg->var_off); + if (false_reg->u32_min_value == val32) + false_reg->u32_min_value++; + if (false_reg->u32_max_value == val32) + false_reg->u32_max_value--; + if (false_reg->s32_min_value == sval32) + false_reg->s32_min_value++; + if (false_reg->s32_max_value == sval32) + false_reg->s32_max_value--; } else { ___mark_reg_known(true_reg, val); true_64off = true_reg->var_off; + if (false_reg->umin_value == val) + false_reg->umin_value++; + if (false_reg->umax_value == val) + false_reg->umax_value--; + if (false_reg->smin_value == sval) + false_reg->smin_value++; + if (false_reg->smax_value == sval) + false_reg->smax_value--; } break; case BPF_JNE: if (is_jmp32) { __mark_reg32_known(false_reg, val32); false_32off = tnum_subreg(false_reg->var_off); + if (true_reg->u32_min_value == val32) + true_reg->u32_min_value++; + if (true_reg->u32_max_value == val32) + true_reg->u32_max_value--; + if (true_reg->s32_min_value == sval32) + true_reg->s32_min_value++; + if (true_reg->s32_max_value == sval32) + true_reg->s32_max_value--; } else { ___mark_reg_known(false_reg, val); false_64off = false_reg->var_off; + if (true_reg->umin_value == val) + true_reg->umin_value++; + if (true_reg->umax_value == val) + true_reg->umax_value--; + if (true_reg->smin_value == sval) + true_reg->smin_value++; + if (true_reg->smax_value == sval) + true_reg->smax_value--; } break; case BPF_JSET:
--
2.43.0