In regs_refine_cond_op(), the BPF_JNE case narrows register bounds without guarding against wrap-around at type boundaries. When umin_value equals U64_MAX, incrementing it wraps to 0, producing an inconsistent bounds state (umin=0, umax=U64_MAX-1). This can be triggered by constructing a register state where: r1 = unknown_byte | 0xFFFFFFFFFFFFFFFE -> var_off = (value=U64_MAX-1, mask=1) -> constrain with JGE U64_MAX -> umin=umax=U64_MAX, tnum non-const -> compare with BPF_JNE const=U64_MAX -> wrap occurs The same issue exists for all {u,s}{min,max}{32,64} variants. Add explicit boundary guards to prevent wrap-around in all cases. Reported-by: Ibrahim Zein Signed-off-by: Ibrahim Zein --- kernel/bpf/verifier.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -17017,22 +17017,34 @@ static void regs_refine_cond_op(...) if (is_jmp32) { - if (reg1->u32_min_value == (u32)val) - reg1->u32_min_value++; - if (reg1->u32_max_value == (u32)val) - reg1->u32_max_value--; - if (reg1->s32_min_value == (s32)val) - reg1->s32_min_value++; - if (reg1->s32_max_value == (s32)val) - reg1->s32_max_value--; + if (reg1->u32_min_value == (u32)val && + reg1->u32_min_value != U32_MAX) + reg1->u32_min_value++; + if (reg1->u32_max_value == (u32)val && + reg1->u32_max_value != 0) + reg1->u32_max_value--; + if (reg1->s32_min_value == (s32)val && + reg1->s32_min_value != S32_MAX) + reg1->s32_min_value++; + if (reg1->s32_max_value == (s32)val && + reg1->s32_max_value != S32_MIN) + reg1->s32_max_value--; } else { - if (reg1->umin_value == (u64)val) - reg1->umin_value++; - if (reg1->umax_value == (u64)val) - reg1->umax_value--; - if (reg1->smin_value == (s64)val) - reg1->smin_value++; - if (reg1->smax_value == (s64)val) - reg1->smax_value--; + if (reg1->umin_value == (u64)val && + reg1->umin_value != U64_MAX) + reg1->umin_value++; + if (reg1->umax_value == (u64)val && + reg1->umax_value != 0) + reg1->umax_value--; + if (reg1->smin_value == (s64)val && + reg1->smin_value != S64_MAX) + reg1->smin_value++; + if (reg1->smax_value == (s64)val && + reg1->smax_value != S64_MIN) + reg1->smax_value--; }