]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bpf: rdonly_untrusted_mem for btf id walk pointer leafs
authorEduard Zingerman <eddyz87@gmail.com>
Fri, 4 Jul 2025 23:03:48 +0000 (16:03 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Mon, 7 Jul 2025 15:25:06 +0000 (08:25 -0700)
When processing a load from a PTR_TO_BTF_ID, the verifier calculates
the type of the loaded structure field based on the load offset.
For example, given the following types:

  struct foo {
    struct foo *a;
    int *b;
  } *p;

The verifier would calculate the type of `p->a` as a pointer to
`struct foo`. However, the type of `p->b` is currently calculated as a
SCALAR_VALUE.

This commit updates the logic for processing PTR_TO_BTF_ID to instead
calculate the type of p->b as PTR_TO_MEM|MEM_RDONLY|PTR_UNTRUSTED.
This change allows further dereferencing of such pointers (using probe
memory instructions).

Suggested-by: Alexei Starovoitov <alexei.starovoitov@gmail.com>
Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20250704230354.1323244-3-eddyz87@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/btf.c
kernel/bpf/verifier.c
tools/testing/selftests/bpf/prog_tests/linked_list.c

index 05fd64a371af1cd993214673d958be8a508c291e..b3c8a95d38fb398b96cd92c1c141f074a6fabf35 100644 (file)
@@ -6915,6 +6915,7 @@ enum bpf_struct_walk_result {
        /* < 0 error */
        WALK_SCALAR = 0,
        WALK_PTR,
+       WALK_PTR_UNTRUSTED,
        WALK_STRUCT,
 };
 
@@ -7156,6 +7157,8 @@ error:
                                        *field_name = mname;
                                return WALK_PTR;
                        }
+
+                       return WALK_PTR_UNTRUSTED;
                }
 
                /* Allow more flexible access within an int as long as
@@ -7228,6 +7231,9 @@ int btf_struct_access(struct bpf_verifier_log *log,
                        *next_btf_id = id;
                        *flag = tmp_flag;
                        return PTR_TO_BTF_ID;
+               case WALK_PTR_UNTRUSTED:
+                       *flag = MEM_RDONLY | PTR_UNTRUSTED;
+                       return PTR_TO_MEM;
                case WALK_SCALAR:
                        return SCALAR_VALUE;
                case WALK_STRUCT:
index 9e8328f40b888f8bc24c45a73a42884256ff087a..87ab00b40d9f1d3ff57d95ea1047a74d3bb0e330 100644 (file)
@@ -2814,6 +2814,11 @@ static int mark_btf_ld_reg(struct bpf_verifier_env *env,
                if (type_may_be_null(flag))
                        regs[regno].id = ++env->id_gen;
                return 0;
+       case PTR_TO_MEM:
+               mark_reg_known_zero(env, regs, regno);
+               regs[regno].type = PTR_TO_MEM | flag;
+               regs[regno].mem_size = 0;
+               return 0;
        default:
                verifier_bug(env, "unexpected reg_type %d in %s\n", reg_type, __func__);
                return -EFAULT;
index 5266c70228631bceb2b1ced16df4c9448848371c..14c5a7ef0e87d0c2cedf04a3b4fd7bd8419b9c43 100644 (file)
@@ -72,7 +72,7 @@ static struct {
        { "new_null_ret", "R0 invalid mem access 'ptr_or_null_'" },
        { "obj_new_acq", "Unreleased reference id=" },
        { "use_after_drop", "invalid mem access 'scalar'" },
-       { "ptr_walk_scalar", "type=scalar expected=percpu_ptr_" },
+       { "ptr_walk_scalar", "type=rdonly_untrusted_mem expected=percpu_ptr_" },
        { "direct_read_lock", "direct access to bpf_spin_lock is disallowed" },
        { "direct_write_lock", "direct access to bpf_spin_lock is disallowed" },
        { "direct_read_head", "direct access to bpf_list_head is disallowed" },