Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: rdonly_untrusted_mem for btf id walk pointer leafs

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>

authored by

Eduard Zingerman and committed by
Alexei Starovoitov
2d5c91e1 b9d44bc9

+12 -1
+6
kernel/bpf/btf.c
··· 6915 6915 /* < 0 error */ 6916 6916 WALK_SCALAR = 0, 6917 6917 WALK_PTR, 6918 + WALK_PTR_UNTRUSTED, 6918 6919 WALK_STRUCT, 6919 6920 }; 6920 6921 ··· 7157 7156 *field_name = mname; 7158 7157 return WALK_PTR; 7159 7158 } 7159 + 7160 + return WALK_PTR_UNTRUSTED; 7160 7161 } 7161 7162 7162 7163 /* Allow more flexible access within an int as long as ··· 7231 7228 *next_btf_id = id; 7232 7229 *flag = tmp_flag; 7233 7230 return PTR_TO_BTF_ID; 7231 + case WALK_PTR_UNTRUSTED: 7232 + *flag = MEM_RDONLY | PTR_UNTRUSTED; 7233 + return PTR_TO_MEM; 7234 7234 case WALK_SCALAR: 7235 7235 return SCALAR_VALUE; 7236 7236 case WALK_STRUCT:
+5
kernel/bpf/verifier.c
··· 2814 2814 if (type_may_be_null(flag)) 2815 2815 regs[regno].id = ++env->id_gen; 2816 2816 return 0; 2817 + case PTR_TO_MEM: 2818 + mark_reg_known_zero(env, regs, regno); 2819 + regs[regno].type = PTR_TO_MEM | flag; 2820 + regs[regno].mem_size = 0; 2821 + return 0; 2817 2822 default: 2818 2823 verifier_bug(env, "unexpected reg_type %d in %s\n", reg_type, __func__); 2819 2824 return -EFAULT;
+1 -1
tools/testing/selftests/bpf/prog_tests/linked_list.c
··· 72 72 { "new_null_ret", "R0 invalid mem access 'ptr_or_null_'" }, 73 73 { "obj_new_acq", "Unreleased reference id=" }, 74 74 { "use_after_drop", "invalid mem access 'scalar'" }, 75 - { "ptr_walk_scalar", "type=scalar expected=percpu_ptr_" }, 75 + { "ptr_walk_scalar", "type=rdonly_untrusted_mem expected=percpu_ptr_" }, 76 76 { "direct_read_lock", "direct access to bpf_spin_lock is disallowed" }, 77 77 { "direct_write_lock", "direct access to bpf_spin_lock is disallowed" }, 78 78 { "direct_read_head", "direct access to bpf_list_head is disallowed" },