1. 20 Dec, 2023 10 commits
    • Andrii Nakryiko's avatar
      bpf: reuse subprog argument parsing logic for subprog call checks · f18c3d88
      Andrii Nakryiko authored
      Remove duplicated BTF parsing logic when it comes to subprog call check.
      Instead, use (potentially cached) results of btf_prepare_func_args() to
      abstract away expectations of each subprog argument in generic terms
      (e.g., "this is pointer to context", or "this is a pointer to memory of
      size X"), and then use those simple high-level argument type
      expectations to validate actual register states to check if they match
      expectations.
      Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/r/20231215011334.2307144-6-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      f18c3d88
    • Andrii Nakryiko's avatar
      bpf: move subprog call logic back to verifier.c · c5a72447
      Andrii Nakryiko authored
      Subprog call logic in btf_check_subprog_call() currently has both a lot
      of BTF parsing logic (which is, presumably, what justified putting it
      into btf.c), but also a bunch of register state checks, some of each
      utilize deep verifier logic helpers, necessarily exported from
      verifier.c: check_ptr_off_reg(), check_func_arg_reg_off(),
      and check_mem_reg().
      
      Going forward, btf_check_subprog_call() will have a minimum of
      BTF-related logic, but will get more internal verifier logic related to
      register state manipulation. So move it into verifier.c to minimize
      amount of verifier-specific logic exposed to btf.c.
      
      We do this move before refactoring btf_check_func_arg_match() to
      preserve as much history post-refactoring as possible.
      
      No functional changes.
      Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/r/20231215011334.2307144-5-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      c5a72447
    • Andrii Nakryiko's avatar
      bpf: prepare btf_prepare_func_args() for handling static subprogs · e26080d0
      Andrii Nakryiko authored
      Generalize btf_prepare_func_args() to support both global and static
      subprogs. We are going to utilize this property in the next patch,
      reusing btf_prepare_func_args() for subprog call logic instead of
      reparsing BTF information in a completely separate implementation.
      
      btf_prepare_func_args() now detects whether subprog is global or static
      makes slight logic adjustments for static func cases, like not failing
      fatally (-EFAULT) for conditions that are allowable for static subprogs.
      
      Somewhat subtle (but major!) difference is the handling of pointer arguments.
      Both global and static functions need to handle special context
      arguments (which are pointers to predefined type names), but static
      subprogs give up on any other pointers, falling back to marking subprog
      as "unreliable", disabling the use of BTF type information altogether.
      
      For global functions, though, we are assuming that such pointers to
      unrecognized types are just pointers to fixed-sized memory region (or
      error out if size cannot be established, like for `void *` pointers).
      
      This patch accommodates these small differences and sets up a stage for
      refactoring in the next patch, eliminating a separate BTF-based parsing
      logic in btf_check_func_arg_match().
      Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/r/20231215011334.2307144-4-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      e26080d0
    • Andrii Nakryiko's avatar
      bpf: reuse btf_prepare_func_args() check for main program BTF validation · 5eccd2db
      Andrii Nakryiko authored
      Instead of btf_check_subprog_arg_match(), use btf_prepare_func_args()
      logic to validate "trustworthiness" of main BPF program's BTF information,
      if it is present.
      
      We ignored results of original BTF check anyway, often times producing
      confusing and ominously-sounding "reg type unsupported for arg#0
      function" message, which has no apparent effect on program correctness
      and verification process.
      
      All the -EFAULT returning sanity checks are already performed in
      check_btf_info_early(), so there is zero reason to have this duplication
      of logic between btf_check_subprog_call() and btf_check_subprog_arg_match().
      Dropping btf_check_subprog_arg_match() simplifies
      btf_check_func_arg_match() further removing `bool processing_call` flag.
      
      One subtle bit that was done by btf_check_subprog_arg_match() was
      potentially marking main program's BTF as unreliable. We do this
      explicitly now with a dedicated simple check, preserving the original
      behavior, but now based on well factored btf_prepare_func_args() logic.
      Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/r/20231215011334.2307144-3-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      5eccd2db
    • Andrii Nakryiko's avatar
      bpf: abstract away global subprog arg preparation logic from reg state setup · 4ba1d0f2
      Andrii Nakryiko authored
      btf_prepare_func_args() is used to understand expectations and
      restrictions on global subprog arguments. But current implementation is
      hard to extend, as it intermixes BTF-based func prototype parsing and
      interpretation logic with setting up register state at subprog entry.
      
      Worse still, those registers are not completely set up inside
      btf_prepare_func_args(), requiring some more logic later in
      do_check_common(). Like calling mark_reg_unknown() and similar
      initialization operations.
      
      This intermixing of BTF interpretation and register state setup is
      problematic. First, it causes duplication of BTF parsing logic for global
      subprog verification (to set up initial state of global subprog) and
      global subprog call sites analysis (when we need to check that whatever
      is being passed into global subprog matches expectations), performed in
      btf_check_subprog_call().
      
      Given we want to extend global func argument with tags later, this
      duplication is problematic. So refactor btf_prepare_func_args() to do
      only BTF-based func proto and args parsing, returning high-level
      argument "expectations" only, with no regard to specifics of register
      state. I.e., if it's a context argument, instead of setting register
      state to PTR_TO_CTX, we return ARG_PTR_TO_CTX enum for that argument as
      "an argument specification" for further processing inside
      do_check_common(). Similarly for SCALAR arguments, PTR_TO_MEM, etc.
      
      This allows to reuse btf_prepare_func_args() in following patches at
      global subprog call site analysis time. It also keeps register setup
      code consistently in one place, do_check_common().
      
      Besides all this, we cache this argument specs information inside
      env->subprog_info, eliminating the need to redo these potentially
      expensive BTF traversals, especially if BPF program's BTF is big and/or
      there are lots of global subprog calls.
      Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/r/20231215011334.2307144-2-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      4ba1d0f2
    • Alexei Starovoitov's avatar
      Merge branch 'bpf-support-to-track-bpf_jne' · c337f237
      Alexei Starovoitov authored
      Menglong Dong says:
      
      ====================
      bpf: support to track BPF_JNE
      
      For now, the reg bounds is not handled for BPF_JNE case, which can cause
      the failure of following case:
      
        /* The type of "a" is u32 */
        if (a > 0 && a < 100) {
          /* the range of the register for a is [0, 99], not [1, 99],
           * and will cause the following error:
           *
           *   invalid zero-sized read
           *
           * as a can be 0.
           */
          bpf_skb_store_bytes(skb, xx, xx, a, 0);
        }
      
      In the code above, "a > 0" will be compiled to "if a == 0 goto xxx". In
      the TRUE branch, the dst_reg will be marked as known to 0. However, in the
      fallthrough(FALSE) branch, the dst_reg will not be handled, which makes
      the [min, max] for a is [0, 99], not [1, 99].
      
      In the 1st patch, we reduce the range of the dst reg if the src reg is a
      const and is exactly the edge of the dst reg For BPF_JNE.
      
      In the 2nd patch, we remove reduplicated s32 casting in "crafted_cases".
      
      In the 3rd patch, we just activate the test case for this logic in
      range_cond(), which is committed by Andrii in the
      commit 88632389 ("selftests/bpf: BPF register range bounds tester").
      
      In the 4th patch, we convert the case above to a testcase and add it to
      verifier_bounds.c.
      
      Changes since v4:
      - add the 2nd patch
      - add "{U32, U32, {0, U32_MAX}, {U32_MAX, U32_MAX}}" that we missed in the
        3rd patch
      - add some comments to the function that we add in the 4th patch
      - add reg_not_equal_const() in the 4th patch
      
      Changes since v3:
      - do some adjustment to the crafted cases that we added in the 2nd patch
      - add the 3rd patch
      
      Changes since v2:
      - fix a typo in the subject of the 1st patch
      - add some comments to the 1st patch, as Eduard advised
      - add some cases to the "crafted_cases"
      
      Changes since v1:
      - simplify the code in the 1st patch
      - introduce the 2nd patch for the testing
      ====================
      
      Link: https://lore.kernel.org/r/20231219134800.1550388-1-menglong8.dong@gmail.comSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      c337f237
    • Menglong Dong's avatar
      selftests/bpf: add testcase to verifier_bounds.c for BPF_JNE · 463ea64e
      Menglong Dong authored
      Add testcase for the logic that the verifier tracks the BPF_JNE for regs.
      The assembly function "reg_not_equal_const()" and "reg_equal_const" that
      we add is exactly converted from the following case:
      
        u32 a = bpf_get_prandom_u32();
        u64 b = 0;
      
        a %= 8;
        /* the "a > 0" here will be optimized to "a != 0" */
        if (a > 0) {
          /* now the range of a should be [1, 7] */
          bpf_skb_store_bytes(skb, 0, &b, a, 0);
        }
      Signed-off-by: default avatarMenglong Dong <menglong8.dong@gmail.com>
      Acked-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/r/20231219134800.1550388-5-menglong8.dong@gmail.comSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      463ea64e
    • Menglong Dong's avatar
      selftests/bpf: activate the OP_NE logic in range_cond() · 31d9cc96
      Menglong Dong authored
      The edge range checking for the registers is supported by the verifier
      now, so we can activate the extended logic in
      tools/testing/selftests/bpf/prog_tests/reg_bounds.c/range_cond() to test
      such logic.
      
      Besides, I added some cases to the "crafted_cases" array for this logic.
      These cases are mainly used to test the edge of the src reg and dst reg.
      
      All reg bounds testings has passed in the SLOW_TESTS mode:
      
      $ export SLOW_TESTS=1 && ./test_progs -t reg_bounds -j
      Summary: 65/18959832 PASSED, 0 SKIPPED, 0 FAILED
      Signed-off-by: default avatarMenglong Dong <menglong8.dong@gmail.com>
      Acked-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/r/20231219134800.1550388-4-menglong8.dong@gmail.comSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      31d9cc96
    • Menglong Dong's avatar
      selftests/bpf: remove reduplicated s32 casting in "crafted_cases" · 1de58483
      Menglong Dong authored
      The "S32_MIN" is already defined with s32 casting, so there is no need
      to do it again.
      Signed-off-by: default avatarMenglong Dong <menglong8.dong@gmail.com>
      Acked-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/r/20231219134800.1550388-3-menglong8.dong@gmail.comSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      1de58483
    • Menglong Dong's avatar
      bpf: make the verifier tracks the "not equal" for regs · d028f875
      Menglong Dong authored
      We can derive some new information for BPF_JNE in regs_refine_cond_op().
      Take following code for example:
      
        /* The type of "a" is u32 */
        if (a > 0 && a < 100) {
          /* the range of the register for a is [0, 99], not [1, 99],
           * and will cause the following error:
           *
           *   invalid zero-sized read
           *
           * as a can be 0.
           */
          bpf_skb_store_bytes(skb, xx, xx, a, 0);
        }
      
      In the code above, "a > 0" will be compiled to "jmp xxx if a == 0". In the
      TRUE branch, the dst_reg will be marked as known to 0. However, in the
      fallthrough(FALSE) branch, the dst_reg will not be handled, which makes
      the [min, max] for a is [0, 99], not [1, 99].
      
      For BPF_JNE, we can reduce the range of the dst reg if the src reg is a
      const and is exactly the edge of the dst reg.
      Signed-off-by: default avatarMenglong Dong <menglong8.dong@gmail.com>
      Acked-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Acked-by: default avatarShung-Hsi Yu <shung-hsi.yu@suse.com>
      Link: https://lore.kernel.org/r/20231219134800.1550388-2-menglong8.dong@gmail.comSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      d028f875
  2. 19 Dec, 2023 20 commits
  3. 18 Dec, 2023 10 commits