Re: [PATCH v2 bpf-next 3/6] bpf: Exit early if reg_bounds_sync gets invalid inputs

Harishankar Vishwanathan
2026-03-24T19:28:47Z

On Mon, Mar 23, 2026 at 2:47 PM Eduard Zingerman <eddyz87@gmail.com> wrote:
>
> On Fri, 2026-03-20 at 17:49 +0100, Paul Chaignon wrote:
>
> [...]
>
> > @@ -2786,8 +2786,13 @@ static void __reg_bound_offset(struct bpf_reg_state *reg)
> > reg->var_off = tnum_or(tnum_clear_subreg(var64_off), var32_off);
> > }
> >
> > +static bool range_bounds_violation(struct bpf_reg_state *reg);
> > +
> > static void reg_bounds_sync(struct bpf_reg_state *reg)
> > {
> > + /* If the input reg_state is invalid, we can exit early */
> > + if (range_bounds_violation(reg))
> > + return;
> > /* We might have learned new bounds from the var_off. */
> > __update_reg_bounds(reg);
> > /* We might have learned something about the sign bit. */
>
> Is it possible for the invariants violation to manifest after
> __update_reg{32,64}_bounds() calls, once cross domain boundaries are
> propagated?

The short answer is yes.

The sub-sync functions, i.e. __update_reg_bounds, __reg_deduce_bounds,
__reg_bound_offset are individually sound (checked by Agni).
This means that they preserve any concrete value x that is contained in all
the range bounds and tnum inputs, after refinement.

But if in the input, there is no concrete value x that is contained in
ALL the range bounds and tnum, then an invariant violation can
manifest. Note that this can happen in the presence
of the current early exit commit, i.e., even if
range_bounds_violation(reg) is false.

For example,

before reg_bounds_sync: s64=[1, 1], tnum=0
after reg_bounds_sync: s64=[1, 0] tnum=0

Could you elaborate on your concern? Did you perhaps imply that we should
be checking for reg_bounds_violation in
simulate_both_branches_taken after each sub-sync function?