• Andrii Nakryiko's avatar
    bpf: try harder to deduce register bounds from different numeric domains · d7f00873
    Andrii Nakryiko authored
    There are cases (caught by subsequent reg_bounds tests in selftests/bpf)
    where performing one round of __reg_deduce_bounds() doesn't propagate
    all the information from, say, s32 to u32 bounds and than from newly
    learned u32 bounds back to u64 and s64. So perform __reg_deduce_bounds()
    twice to make sure such derivations are propagated fully after
    reg_bounds_sync().
    
    One such example is test `(s64)[0xffffffff00000001; 0] (u64)<
    0xffffffff00000000` from selftest patch from this patch set. It demonstrates an
    intricate dance of u64 -> s64 -> u64 -> u32 bounds adjustments, which requires
    two rounds of __reg_deduce_bounds(). Here are corresponding refinement log from
    selftest, showing evolution of knowledge.
    
    REFINING (FALSE R1) (u64)SRC=[0xffffffff00000000; U64_MAX] (u64)DST_OLD=[0; U64_MAX] (u64)DST_NEW=[0xffffffff00000000; U64_MAX]
    REFINING (FALSE R1) (u64)SRC=[0xffffffff00000000; U64_MAX] (s64)DST_OLD=[0xffffffff00000001; 0] (s64)DST_NEW=[0xffffffff00000001; -1]
    REFINING (FALSE R1) (s64)SRC=[0xffffffff00000001; -1] (u64)DST_OLD=[0xffffffff00000000; U64_MAX] (u64)DST_NEW=[0xffffffff00000001; U64_MAX]
    REFINING (FALSE R1) (u64)SRC=[0xffffffff00000001; U64_MAX] (u32)DST_OLD=[0; U32_MAX] (u32)DST_NEW=[1; U32_MAX]
    
    R1 initially has smin/smax set to [0xffffffff00000001; -1], while umin/umax is
    unknown. After (u64)< comparison, in FALSE branch we gain knowledge that
    umin/umax is [0xffffffff00000000; U64_MAX]. That causes smin/smax to learn that
    zero can't happen and upper bound is -1. Then smin/smax is adjusted from
    umin/umax improving lower bound from 0xffffffff00000000 to 0xffffffff00000001.
    And then eventually umin32/umax32 bounds are drived from umin/umax and become
    [1; U32_MAX].
    
    Selftest in the last patch is actually implementing a multi-round fixed-point
    convergence logic, but so far all the tests are handled by two rounds of
    reg_bounds_sync() on the verifier state, so we keep it simple for now.
    Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
    Link: https://lore.kernel.org/r/20231102033759.2541186-9-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
    d7f00873
verifier.c 622 KB