1. 21 Nov, 2023 2 commits
  2. 20 Nov, 2023 1 commit
    • Andrii Nakryiko's avatar
      selftests/bpf: reduce verboseness of reg_bounds selftest logs · 57b97ecb
      Andrii Nakryiko authored
      Reduce verboseness of test_progs' output in reg_bounds set of tests with
      two changes.
      
      First, instead of each different operator (<, <=, >, ...) being it's own
      subtest, combine all different ops for the same (x, y, init_t, cond_t)
      values into single subtest. Instead of getting 6 subtests, we get one
      generic one, e.g.:
      
        #192/53  reg_bounds_crafted/(s64)[0xffffffffffffffff; 0] (s64)<op> 0xffffffff00000000:OK
      
      Second, for random generated test cases, treat all of them as a single
      test to eliminate very verbose output with random values in them. So now
      we'll just get one line per each combination of (init_t, cond_t),
      instead of 6 x 25 = 150 subtests before this change:
      
        #225     reg_bounds_rand_consts_s32_s32:OK
      
      Given we reduce verboseness so much, it makes sense to do a bit more
      random testing, so we also bump default number of random tests to 100,
      up from 25. This doesn't increase runtime significantly, especially in
      parallelized mode.
      
      With all the above changes we still make sure that we have all the
      information necessary for reproducing test case if it happens to fail.
      That includes reporting random seed and specific operator that is
      failing. Those will only be printed to console if related test/subtest
      fails, so it doesn't have any added verboseness implications.
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/r/20231120180452.145849-1-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      57b97ecb
  3. 19 Nov, 2023 4 commits
  4. 18 Nov, 2023 9 commits
  5. 17 Nov, 2023 1 commit
  6. 15 Nov, 2023 15 commits
    • Puranjay Mohan's avatar
      bpf: Remove test for MOVSX32 with offset=32 · 5fa201f3
      Puranjay Mohan authored
      MOVSX32 only supports sign extending 8-bit and 16-bit operands into 32
      bit operands. The "ALU_MOVSX | BPF_W" test tries to sign extend a 32 bit
      operand into a 32 bit operand which is equivalent to a normal BPF_MOV.
      
      Remove this test as it tries to run an invalid instruction.
      
      Fixes: daabb2b0 ("bpf/tests: add tests for cpuv4 instructions")
      Signed-off-by: default avatarPuranjay Mohan <puranjay12@gmail.com>
      Reported-by: default avatarkernel test robot <oliver.sang@intel.com>
      Closes: https://lore.kernel.org/oe-lkp/202310111838.46ff5b6a-oliver.sang@intel.comAcked-by: default avatarStanislav Fomichev <sdf@google.com>
      Acked-by: default avatarYonghong Song <yonghong.song@linux.dev>
      Link: https://lore.kernel.org/r/20231110175150.87803-1-puranjay12@gmail.comSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      5fa201f3
    • Alexei Starovoitov's avatar
      Merge branch 'bpf-register-bounds-range-vs-range-support' · 9cea90c0
      Alexei Starovoitov authored
      Andrii Nakryiko says:
      
      ====================
      BPF register bounds range vs range support
      
      This patch set is a continuation of work started in [0]. It adds a big set of
      manual, auto-generated, and now also random test cases validating BPF
      verifier's register bounds tracking and deduction logic.
      
      First few patches generalize verifier's logic to handle conditional jumps and
      corresponding range adjustments in case when two non-const registers are
      compared to each other. Patch #1 generalizes reg_set_min_max() portion, while
      patch #2 does the same for is_branch_taken() part of the overall solution.
      
      Patch #3 improves equality and inequality for cases when BPF program code
      mixes 64-bit and 32-bit uses of the same register. Depending on specific
      sequence, it's possible to get to the point where u64/s64 bounds will be very
      generic (e.g., after signed 32-bit comparison), while we still keep pretty
      tight u32/s32 bounds. If in such state we proceed with 32-bit equality or
      inequality comparison, reg_set_min_max() might have to deal with adjusting s32
      bounds for two registers that don't overlap, which breaks reg_set_min_max().
      This doesn't manifest in <range> vs <const> cases, because if that happens
      reg_set_min_max() in effect will force s32 bounds to be a new "impossible"
      constant (from original smin32/smax32 bounds point of view). Things get tricky
      when we have <range> vs <range> adjustments, so instead of trying to somehow
      make sense out of such situations, it's best to detect such impossible
      situations and prune the branch that can't be taken in is_branch_taken()
      logic.  This equality/inequality was the only such category of situations with
      auto-generated tests added later in the patch set.
      
      But when we start mixing arithmetic operations in different numeric domains
      and conditionals, things get even hairier. So, patch #4 adds sanity checking
      logic after all ALU/ALU64, JMP/JMP32, and LDX operations. By default, instead
      of failing verification, we conservatively reset range bounds to unknown
      values, reporting violation in verifier log (if verbose logs are requested).
      But to aid development, detection, and debugging, we also introduce a new test
      flag, BPF_F_TEST_SANITY_STRICT, which triggers verification failure on range
      sanity violation.
      
      Patch #11 sets BPF_F_TEST_SANITY_STRICT by default for test_progs and
      test_verifier. Patch #12 adds support for controlling this in veristat for
      testing with production BPF object files.
      
      Getting back to BPF verifier, patches #5 and #6 complete verifier's range
      tracking logic clean up. See respective patches for details.
      
      With kernel-side taken care of, we move to testing. We start with building
      a tester that validates existing <range> vs <scalar> verifier logic for range
      bounds. Patch #7 implements an initial version of such a tester. We guard
      millions of generated tests behind SLOW_TESTS=1 envvar requirement, but also
      have a relatively small number of tricky cases that came up during development
      and debugging of this work. Those will be executed as part of a normal
      test_progs run.
      
      Patch #8 simulates more nuanced JEQ/JNE logic we added to verifier in patch #3.
      Patch #9 adds <range> vs <range> "slow tests".
      
      Patch #10 is a completely new one, it adds a bunch of randomly generated cases
      to be run normally, without SLOW_TESTS=1 guard. This should help to get
      a bunch of cover, and hopefully find some remaining latent problems if
      verifier proactively as part of normal BPF CI runs.
      
      Finally, a tiny test which was, amazingly, an initial motivation for this
      whole work, is added in lucky patch #13, demonstrating how verifier is now
      smart enough to track actual number of elements in the array and won't require
      additional checks on loop iteration variable inside the bpf_for() open-coded
      iterator loop.
      
        [0] https://patchwork.kernel.org/project/netdevbpf/list/?series=798308&state=*
      
      v1->v2:
        - use x < y => y > x property to minimize reg_set_min_max (Eduard);
        - fix for JEQ/JNE logic in reg_bounds.c (Eduard);
        - split BPF_JSET and !BPF_JSET cases handling (Shung-Hsi);
        - adjustments to reg_bounds.c to make it easier to follow (Alexei);
        - added acks (Eduard, Shung-Hsi).
      ====================
      
      Link: https://lore.kernel.org/r/20231112010609.848406-1-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      9cea90c0
    • Andrii Nakryiko's avatar
      selftests/bpf: add iter test requiring range x range logic · 882e3d87
      Andrii Nakryiko authored
      Add a simple verifier test that requires deriving reg bounds for one
      register from another register that's not a constant. This is
      a realistic example of iterating elements of an array with fixed maximum
      number of elements, but smaller actual number of elements.
      
      This small example was an original motivation for doing this whole patch
      set in the first place, yes.
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/r/20231112010609.848406-14-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      882e3d87
    • Andrii Nakryiko's avatar
      veristat: add ability to set BPF_F_TEST_SANITY_STRICT flag with -r flag · a5c57f81
      Andrii Nakryiko authored
      Add a new flag -r (--test-sanity), similar to -t (--test-states), to add
      extra BPF program flags when loading BPF programs.
      
      This allows to use veristat to easily catch sanity violations in
      production BPF programs.
      
      reg_bounds tests are also enforcing BPF_F_TEST_SANITY_STRICT flag now.
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/r/20231112010609.848406-13-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      a5c57f81
    • Andrii Nakryiko's avatar
      selftests/bpf: set BPF_F_TEST_SANITY_SCRIPT by default · 8c5677f8
      Andrii Nakryiko authored
      Make sure to set BPF_F_TEST_SANITY_STRICT program flag by default across
      most verifier tests (and a bunch of others that set custom prog flags).
      
      There are currently two tests that do fail validation, if enforced
      strictly: verifier_bounds/crossing_64_bit_signed_boundary_2 and
      verifier_bounds/crossing_32_bit_signed_boundary_2. To accommodate them,
      we teach test_loader a flag negation:
      
      __flag(!<flagname>) will *clear* specified flag, allowing easy opt-out.
      
      We apply __flag(!BPF_F_TEST_SANITY_STRICT) to these to tests.
      
      Also sprinkle BPF_F_TEST_SANITY_STRICT everywhere where we already set
      test-only BPF_F_TEST_RND_HI32 flag, for completeness.
      Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/r/20231112010609.848406-12-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      8c5677f8
    • Andrii Nakryiko's avatar
      selftests/bpf: add randomized reg_bounds tests · dab16659
      Andrii Nakryiko authored
      Add random cases generation to reg_bounds.c and run them without
      SLOW_TESTS=1 to increase a chance of BPF CI catching latent issues.
      Suggested-by: default avatarAlexei Starovoitov <ast@kernel.org>
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/r/20231112010609.848406-11-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      dab16659
    • Andrii Nakryiko's avatar
      selftests/bpf: add range x range test to reg_bounds · 2b0d204e
      Andrii Nakryiko authored
      Now that verifier supports range vs range bounds adjustments, validate
      that by checking each generated range against every other generated
      range, across all supported operators (everything by JSET).
      
      We also add few cases that were problematic during development either
      for verifier or for selftest's range tracking implementation.
      
      Note that we utilize the same trick with splitting everything into
      multiple independent parallelizable tests, but init_t and cond_t. This
      brings down verification time in parallel mode from more than 8 hours
      down to less that 1.5 hours. 106 million cases were successfully
      validate for range vs range logic, in addition to about 7 million range
      vs const cases, added in earlier patch.
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/r/20231112010609.848406-10-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      2b0d204e
    • Andrii Nakryiko's avatar
      selftests/bpf: adjust OP_EQ/OP_NE handling to use subranges for branch taken · 774f94c5
      Andrii Nakryiko authored
      Similar to kernel-side BPF verifier logic enhancements, use 32-bit
      subrange knowledge for is_branch_taken() logic in reg_bounds selftests.
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
      Link: https://lore.kernel.org/r/20231112010609.848406-9-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      774f94c5
    • Andrii Nakryiko's avatar
      selftests/bpf: BPF register range bounds tester · 88632389
      Andrii Nakryiko authored
      Add test to validate BPF verifier's register range bounds tracking logic.
      
      The main bulk is a lot of auto-generated tests based on a small set of
      seed values for lower and upper 32 bits of full 64-bit values.
      Currently we validate only range vs const comparisons, but the idea is
      to start validating range over range comparisons in subsequent patch set.
      
      When setting up initial register ranges we treat registers as one of
      u64/s64/u32/s32 numeric types, and then independently perform conditional
      comparisons based on a potentially different u64/s64/u32/s32 types. This
      tests lots of tricky cases of deriving bounds information across
      different numeric domains.
      
      Given there are lots of auto-generated cases, we guard them behind
      SLOW_TESTS=1 envvar requirement, and skip them altogether otherwise.
      With current full set of upper/lower seed value, all supported
      comparison operators and all the combinations of u64/s64/u32/s32 number
      domains, we get about 7.7 million tests, which run in about 35 minutes
      on my local qemu instance without parallelization. But we also split
      those tests by init/cond numeric types, which allows to rely on
      test_progs's parallelization of tests with `-j` option, getting run time
      down to about 5 minutes on 8 cores. It's still something that shouldn't
      be run during normal test_progs run.  But we can run it a reasonable
      time, and so perhaps a nightly CI test run (once we have it) would be
      a good option for this.
      
      We also add a small set of tricky conditions that came up during
      development and triggered various bugs or corner cases in either
      selftest's reimplementation of range bounds logic or in verifier's logic
      itself. These are fast enough to be run as part of normal test_progs
      test run and are great for a quick sanity checking.
      
      Let's take a look at test output to understand what's going on:
      
        $ sudo ./test_progs -t reg_bounds_crafted
        #191/1   reg_bounds_crafted/(u64)[0; 0xffffffff] (u64)< 0:OK
        ...
        #191/115 reg_bounds_crafted/(u64)[0; 0x17fffffff] (s32)< 0:OK
        ...
        #191/137 reg_bounds_crafted/(u64)[0xffffffff; 0x100000000] (u64)== 0:OK
      
      Each test case is uniquely and fully described by this generated string.
      E.g.: "(u64)[0; 0x17fffffff] (s32)< 0". This means that we
      initialize a register (R6) in such a way that verifier knows that it can
      have a value in [(u64)0; (u64)0x17fffffff] range. Another
      register (R7) is also set up as u64, but this time a constant (zero in
      this case). They then are compared using 32-bit signed < operation.
      Resulting TRUE/FALSE branches are evaluated (including cases where it's
      known that one of the branches will never be taken, in which case we
      validate that verifier also determines this as a dead code). Test
      validates that verifier's final register state matches expected state
      based on selftest's own reg_state logic, implemented from scratch for
      cross-checking purposes.
      
      These test names can be conveniently used for further debugging, and if -vv
      verboseness is requested we can get a corresponding verifier log (with
      mark_precise logs filtered out as irrelevant and distracting). Example below is
      slightly redacted for brevity, omitting irrelevant register output in
      some places, marked with [...].
      
        $ sudo ./test_progs -a 'reg_bounds_crafted/(u32)[0; U32_MAX] (s32)< -1' -vv
        ...
        VERIFIER LOG:
        ========================
        func#0 @0
        0: R1=ctx(off=0,imm=0) R10=fp0
        0: (05) goto pc+2
        3: (85) call bpf_get_current_pid_tgid#14      ; R0_w=scalar()
        4: (bc) w6 = w0                       ; R0_w=scalar() R6_w=scalar(smin=0,smax=umax=4294967295,var_off=(0x0; 0xffffffff))
        5: (85) call bpf_get_current_pid_tgid#14      ; R0_w=scalar()
        6: (bc) w7 = w0                       ; R0_w=scalar() R7_w=scalar(smin=0,smax=umax=4294967295,var_off=(0x0; 0xffffffff))
        7: (b4) w1 = 0                        ; R1_w=0
        8: (b4) w2 = -1                       ; R2=4294967295
        9: (ae) if w6 < w1 goto pc-9
        9: R1=0 R6=scalar(smin=0,smax=umax=4294967295,var_off=(0x0; 0xffffffff))
        10: (2e) if w6 > w2 goto pc-10
        10: R2=4294967295 R6=scalar(smin=0,smax=umax=4294967295,var_off=(0x0; 0xffffffff))
        11: (b4) w1 = -1                      ; R1_w=4294967295
        12: (b4) w2 = -1                      ; R2_w=4294967295
        13: (ae) if w7 < w1 goto pc-13        ; R1_w=4294967295 R7=4294967295
        14: (2e) if w7 > w2 goto pc-14
        14: R2_w=4294967295 R7=4294967295
        15: (bc) w0 = w6                      ; [...] R6=scalar(id=1,smin=0,smax=umax=4294967295,var_off=(0x0; 0xffffffff))
        16: (bc) w0 = w7                      ; [...] R7=4294967295
        17: (ce) if w6 s< w7 goto pc+3        ; R6=scalar(id=1,smin=0,smax=umax=4294967295,smin32=-1,var_off=(0x0; 0xffffffff)) R7=4294967295
        18: (bc) w0 = w6                      ; [...] R6=scalar(id=1,smin=0,smax=umax=4294967295,smin32=-1,var_off=(0x0; 0xffffffff))
        19: (bc) w0 = w7                      ; [...] R7=4294967295
        20: (95) exit
      
        from 17 to 21: [...]
        21: (bc) w0 = w6                      ; [...] R6=scalar(id=1,smin=umin=umin32=2147483648,smax=umax=umax32=4294967294,smax32=-2,var_off=(0x80000000; 0x7fffffff))
        22: (bc) w0 = w7                      ; [...] R7=4294967295
        23: (95) exit
      
        from 13 to 1: [...]
        1: [...]
        1: (b7) r0 = 0                        ; R0_w=0
        2: (95) exit
        processed 24 insns (limit 1000000) max_states_per_insn 0 total_states 2 peak_states 2 mark_read 1
        =====================
      
      Verifier log above is for `(u32)[0; U32_MAX] (s32)< -1` use cases, where u32
      range is used for initialization, followed by signed < operator. Note
      how we use w6/w7 in this case for register initialization (it would be
      R6/R7 for 64-bit types) and then `if w6 s< w7` for comparison at
      instruction #17. It will be `if R6 < R7` for 64-bit unsigned comparison.
      Above example gives a good impression of the overall structure of a BPF
      programs generated for reg_bounds tests.
      
      In the future, this "framework" can be extended to test not just
      conditional jumps, but also arithmetic operations. Adding randomized
      testing is another possibility.
      
      Some implementation notes. We basically have our own generics-like
      operations on numbers, where all the numbers are stored in u64, but how
      they are interpreted is passed as runtime argument enum num_t. Further,
      `struct range` represents a bounds range, and those are collected
      together into a minimal `struct reg_state`, which collects range bounds
      across all four numberical domains: u64, s64, u32, s64.
      
      Based on these primitives and `enum op` representing possible
      conditional operation (<, <=, >, >=, ==, !=), there is a set of generic
      helpers to perform "range arithmetics", which is used to maintain struct
      reg_state. We simulate what verifier will do for reg bounds of R6 and R7
      registers using these range and reg_state primitives. Simulated
      information is used to determine branch taken conclusion and expected
      exact register state across all four number domains.
      
      Implementation of "range arithmetics" is more generic than what verifier
      is currently performing: it allows range over range comparisons and
      adjustments. This is the intended end goal of this patch set overall and verifier
      logic is enhanced in subsequent patches in this series to handle range
      vs range operations, at which point selftests are extended to validate
      these conditions as well. For now it's range vs const cases only.
      
      Note that tests are split into multiple groups by their numeric types
      for initialization of ranges and for comparison operation. This allows
      to use test_progs's -j parallelization to speed up tests, as we now have
      16 groups of parallel running tests. Overall reduction of running time
      that allows is pretty good, we go down from more than 30 minutes to
      slightly less than 5 minutes running time.
      Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Acked-by: default avatarShung-Hsi Yu <shung-hsi.yu@suse.com>
      Link: https://lore.kernel.org/r/20231112010609.848406-8-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      88632389
    • Andrii Nakryiko's avatar
      bpf: make __reg{32,64}_deduce_bounds logic more robust · cf5fe3c7
      Andrii Nakryiko authored
      This change doesn't seem to have any effect on selftests and production
      BPF object files, but we preemptively try to make it more robust.
      
      First, "learn sign from signed bounds" comment is misleading, as we are
      learning not just sign, but also values.
      
      Second, we simplify the check for determining whether entire range is
      positive or negative similarly to other checks added earlier, using
      appropriate u32/u64 cast and single comparisons. As explain in comments
      in __reg64_deduce_bounds(), the checks are equivalent.
      
      Last but not least, smin/smax and s32_min/s32_max reassignment based on
      min/max of both umin/umax and smin/smax (and 32-bit equivalents) is hard
      to explain and justify. We are updating unsigned bounds from signed
      bounds, why would we update signed bounds at the same time? This might
      be correct, but it's far from obvious why and the code or comments don't
      try to justify this. Given we've added a separate deduction of signed
      bounds from unsigned bounds earlier, this seems at least redundant, if
      not just wrong.
      
      In short, we remove doubtful pieces, and streamline the rest to follow
      the logic and approach of the rest of reg_bounds_sync() checks.
      Acked-by: default avatarShung-Hsi Yu <shung-hsi.yu@suse.com>
      Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/r/20231112010609.848406-7-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      cf5fe3c7
    • Andrii Nakryiko's avatar
      bpf: remove redundant s{32,64} -> u{32,64} deduction logic · 3cf98cf5
      Andrii Nakryiko authored
      Equivalent checks were recently added in more succinct and, arguably,
      safer form in:
        - f188765f23a5 ("bpf: derive smin32/smax32 from umin32/umax32 bounds");
        - 2e74aef782d3 ("bpf: derive smin/smax from umin/max bounds").
      
      The checks we are removing in this patch set do similar checks to detect
      if entire u32/u64 range has signed bit set or not set, but does it with
      two separate checks.
      
      Further, we forcefully overwrite either smin or smax (and 32-bit equvalents)
      without applying normal min/max intersection logic. It's not clear why
      that would be correct in all cases and seems to work by accident. This
      logic is also "gated" by previous signed -> unsigned derivation, which
      returns early.
      
      All this is quite confusing and seems error-prone, while we already have
      at least equivalent checks happening earlier. So remove this duplicate
      and error-prone logic to simplify things a bit.
      Acked-by: default avatarShung-Hsi Yu <shung-hsi.yu@suse.com>
      Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/r/20231112010609.848406-6-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      3cf98cf5
    • Andrii Nakryiko's avatar
      bpf: add register bounds sanity checks and sanitization · 5f99f312
      Andrii Nakryiko authored
      Add simple sanity checks that validate well-formed ranges (min <= max)
      across u64, s64, u32, and s32 ranges. Also for cases when the value is
      constant (either 64-bit or 32-bit), we validate that ranges and tnums
      are in agreement.
      
      These bounds checks are performed at the end of BPF_ALU/BPF_ALU64
      operations, on conditional jumps, and for LDX instructions (where subreg
      zero/sign extension is probably the most important to check). This
      covers most of the interesting cases.
      
      Also, we validate the sanity of the return register when manually
      adjusting it for some special helpers.
      
      By default, sanity violation will trigger a warning in verifier log and
      resetting register bounds to "unbounded" ones. But to aid development
      and debugging, BPF_F_TEST_SANITY_STRICT flag is added, which will
      trigger hard failure of verification with -EFAULT on register bounds
      violations. This allows selftests to catch such issues. veristat will
      also gain a CLI option to enable this behavior.
      Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Acked-by: default avatarShung-Hsi Yu <shung-hsi.yu@suse.com>
      Link: https://lore.kernel.org/r/20231112010609.848406-5-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      5f99f312
    • Andrii Nakryiko's avatar
      bpf: enhance BPF_JEQ/BPF_JNE is_branch_taken logic · be41a203
      Andrii Nakryiko authored
      Use 32-bit subranges to prune some 64-bit BPF_JEQ/BPF_JNE conditions
      that otherwise would be "inconclusive" (i.e., is_branch_taken() would
      return -1). This can happen, for example, when registers are initialized
      as 64-bit u64/s64, then compared for inequality as 32-bit subregisters,
      and then followed by 64-bit equality/inequality check. That 32-bit
      inequality can establish some pattern for lower 32 bits of a register
      (e.g., s< 0 condition determines whether the bit #31 is zero or not),
      while overall 64-bit value could be anything (according to a value range
      representation).
      
      This is not a fancy quirky special case, but actually a handling that's
      necessary to prevent correctness issue with BPF verifier's range
      tracking: set_range_min_max() assumes that register ranges are
      non-overlapping, and if that condition is not guaranteed by
      is_branch_taken() we can end up with invalid ranges, where min > max.
      
        [0] https://lore.kernel.org/bpf/CACkBjsY2q1_fUohD7hRmKGqv1MV=eP2f6XK8kjkYNw7BaiF8iQ@mail.gmail.com/Acked-by: default avatarShung-Hsi Yu <shung-hsi.yu@suse.com>
      Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/r/20231112010609.848406-4-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      be41a203
    • Andrii Nakryiko's avatar
      bpf: generalize is_scalar_branch_taken() logic · 96381879
      Andrii Nakryiko authored
      Generalize is_branch_taken logic for SCALAR_VALUE register to handle
      cases when both registers are not constants. Previously supported
      <range> vs <scalar> cases are a natural subset of more generic <range>
      vs <range> set of cases.
      
      Generalized logic relies on straightforward segment intersection checks.
      Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Acked-by: default avatarShung-Hsi Yu <shung-hsi.yu@suse.com>
      Link: https://lore.kernel.org/r/20231112010609.848406-3-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      96381879
    • Andrii Nakryiko's avatar
      bpf: generalize reg_set_min_max() to handle non-const register comparisons · 67420501
      Andrii Nakryiko authored
      Generalize bounds adjustment logic of reg_set_min_max() to handle not
      just register vs constant case, but in general any register vs any
      register cases. For most of the operations it's trivial extension based
      on range vs range comparison logic, we just need to properly pick
      min/max of a range to compare against min/max of the other range.
      
      For BPF_JSET we keep the original capabilities, just make sure JSET is
      integrated in the common framework. This is manifested in the
      internal-only BPF_JSET + BPF_X "opcode" to allow for simpler and more
      uniform rev_opcode() handling. See the code for details. This allows to
      reuse the same code exactly both for TRUE and FALSE branches without
      explicitly handling both conditions with custom code.
      
      Note also that now we don't need a special handling of BPF_JEQ/BPF_JNE
      case none of the registers are constants. This is now just a normal
      generic case handled by reg_set_min_max().
      
      To make tnum handling cleaner, tnum_with_subreg() helper is added, as
      that's a common operator when dealing with 32-bit subregister bounds.
      This keeps the overall logic much less noisy when it comes to tnums.
      Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Acked-by: default avatarShung-Hsi Yu <shung-hsi.yu@suse.com>
      Link: https://lore.kernel.org/r/20231112010609.848406-2-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      67420501
  7. 14 Nov, 2023 8 commits