From: Daniel Borkmann <daniel@iogearbox.net> mainline inclusion from mainline-v7.3-rc2 commit ee9ad135b2087f9335eed97d062f5853e70f89fe category: bugfix bugzilla: https://atomgit.com/openeuler/kernel/issues/10047 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- check_ptr_to_btf_access() allows the program to store before the default BTF access path gets to reject a non read access. ac65c710cc64 ("bpf: Reject writes through untrusted BTF pointers") closed that for a PTR_UNTRUSTED pointer, but a bare PTR_TO_BTF_ID may fault on a dereference just the same and is let through. A BPF_LDX gets the BPF_PROBE_MEM rewrite in bpf_convert_ctx_accesses() and a bad address is handled, but a BPF_STX does not and cannot, there is no probed store to rewrite. The store is emitted as a plain one without an exception table entry and a bad address panics the kernel. A bpf_qdisc program can reach this, bpf_qdisc_btf_struct_access() permits a write to Qdisc::limit and Qdisc::next_sched is a plain struct Qdisc pointer which the walk turns into the compat type: struct Qdisc *next = sch->next_sched; next->limit = 1000; BUG: kernel NULL pointer dereference, address: 0000000000000014 RIP: 0010:bpf_prog_c6e14e7f32c8e325_bpf_fifo_enqueue+0x3a/0x12b Code: [...] bf e8 03 00 00 <89> 7e 14 41 8b 7f 14 [...] Kernel panic - not syncing: Fatal exception in interrupt Fix by widen the check to bpf_may_fault_on_deref() so that it covers both. Fixes: 27ae7997a661 ("bpf: Introduce BPF_PROG_TYPE_STRUCT_OPS") Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Eduard Zingerman <eddyz87@gmail.com> Link: https://lore.kernel.org/bpf/20260814215301.709827-3-daniel@iogearbox.net Conflicts: include/linux/bpf_verifier.h [Add bpf_may_fault_on_deref helper] Signed-off-by: Pu Lehui <pulehui@huawei.com> --- include/linux/bpf_verifier.h | 10 ++++++++++ kernel/bpf/verifier.c | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index eeef504067e6..6e8b9391a631 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -840,6 +840,16 @@ static inline u32 type_flag(u32 type) return type & ~BPF_BASE_TYPE_MASK; } +static inline bool bpf_may_fault_on_deref(enum bpf_reg_type type) +{ + /* + * The pointer types which must not be dereferenced without fault + * protection, that is, the ones bpf_convert_ctx_accesses() has to + * turn a BPF_LDX into a BPF_PROBE_MEM one for. + */ + return type == PTR_TO_BTF_ID || (type_flag(type) & PTR_UNTRUSTED); +} + /* only use after check_attach_btf_id() */ static inline enum bpf_prog_type resolve_prog_type(const struct bpf_prog *prog) { diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 9b2008aab1ea..f46aad9c9b47 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -6602,7 +6602,7 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env, return -EACCES; } - if (atype != BPF_READ && (type_flag(reg->type) & PTR_UNTRUSTED)) { + if (atype != BPF_READ && bpf_may_fault_on_deref(reg->type)) { verbose(env, "only read is supported\n"); return -EACCES; } -- 2.34.1