From: Daniel Borkmann <daniel@iogearbox.net>
To: eddyz87@gmail.com
Cc: memxor@gmail.com, bpf@vger.kernel.org
Subject: [PATCH bpf-next v2 4/6] bpf: Rewrite any fault prone load out of a mem or btf_id pointer
Date: Fri, 14 Aug 2026 23:52:58 +0200 [thread overview]
Message-ID: <20260814215301.709827-4-daniel@iogearbox.net> (raw)
In-Reply-To: <20260814215301.709827-1-daniel@iogearbox.net>
bpf_convert_ctx_accesses() turns a BPF_LDX into a BPF_PROBE_MEM one by
matching the type recorded for the insn against a list of exact pointer
types. The list cannot keep up with the flag combinations the verifier
produces, and a type which is missing from it ends up as a plain load
without an exception table entry, so a bad address panics the kernel
instead of being handled.
Two such types exist today and are reachable:
- PTR_TO_BTF_ID | PTR_UNTRUSTED | MEM_ALLOC | NON_OWN_REF
- PTR_TO_BTF_ID | PTR_UNTRUSTED | MEM_RCU
Rather than adding the two, just drop the list and state the property
itself in the default case of the switch. This is a superset of what
the list matched, the untrusted PTR_TO_MEM does not have to carry
MEM_RDONLY for it anymore, and it stays in sync with the verifier side
which uses the same match in save_aux_ptr_type() and reg_type_mismatch_ok().
Assert that a fault prone type which does not get the rewrite for whatever
reason is rejected at load time rather than left to fault at runtime to
catch any future cases.
Fixes: 1b12171533a9 ("bpf: Mark direct ld of stashed bpf_{rb,list}_node as non-owning ref")
Fixes: 6fcd486b3a0a ("bpf: Refactor RCU enforcement in the verifier.")
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
v1 -> v2:
- new patch, don't match on full types (Eduard)
include/linux/bpf_verifier.h | 11 +++++++++
kernel/bpf/fixups.c | 47 ++++++++++++++++++++----------------
kernel/bpf/verifier.c | 15 ++----------
3 files changed, 39 insertions(+), 34 deletions(-)
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 114ae4540d2c..7239cffa7b51 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -1297,6 +1297,17 @@ static inline u32 type_flag(u32 type)
return type & ~BPF_BASE_TYPE_MASK;
}
+static inline bool bpf_is_ptr_to_mem_or_btf_id(enum bpf_reg_type type)
+{
+ switch (base_type(type)) {
+ case PTR_TO_MEM:
+ case PTR_TO_BTF_ID:
+ return true;
+ default:
+ return false;
+ }
+}
+
static inline bool bpf_may_fault_on_deref(enum bpf_reg_type type)
{
/*
diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c
index c4bd70befbb5..796fba0505dc 100644
--- a/kernel/bpf/fixups.c
+++ b/kernel/bpf/fixups.c
@@ -811,6 +811,7 @@ int bpf_convert_ctx_accesses(struct bpf_verifier_env *env)
for (i = 0; i < insn_cnt; i++, insn++) {
bpf_convert_ctx_access_t convert_ctx_access;
+ enum bpf_reg_type ptr_type;
u8 mode;
if (env->insn_aux_data[i + delta].nospec) {
@@ -903,7 +904,8 @@ int bpf_convert_ctx_accesses(struct bpf_verifier_env *env)
continue;
}
- switch ((int)env->insn_aux_data[i + delta].ptr_type) {
+ ptr_type = env->insn_aux_data[i + delta].ptr_type;
+ switch ((int)ptr_type) {
case PTR_TO_CTX:
if (!ops->convert_ctx_access)
continue;
@@ -919,26 +921,6 @@ int bpf_convert_ctx_accesses(struct bpf_verifier_env *env)
case PTR_TO_XDP_SOCK:
convert_ctx_access = bpf_xdp_sock_convert_ctx_access;
break;
- case PTR_TO_BTF_ID:
- case PTR_TO_BTF_ID | PTR_UNTRUSTED:
- /* PTR_TO_BTF_ID | MEM_ALLOC always has a valid lifetime, unlike
- * PTR_TO_BTF_ID, and an active referenced id, but the same cannot
- * be said once it is marked PTR_UNTRUSTED, hence we must handle
- * any faults for loads into such types. BPF_WRITE is disallowed
- * for this case.
- */
- case PTR_TO_BTF_ID | MEM_ALLOC | PTR_UNTRUSTED:
- case PTR_TO_MEM | MEM_RDONLY | PTR_UNTRUSTED:
- if (type == BPF_READ) {
- if (BPF_MODE(insn->code) == BPF_MEM)
- insn->code = BPF_LDX | BPF_PROBE_MEM |
- BPF_SIZE((insn)->code);
- else
- insn->code = BPF_LDX | BPF_PROBE_MEMSX |
- BPF_SIZE((insn)->code);
- env->prog->aux->num_exentries++;
- }
- continue;
case PTR_TO_ARENA:
if (BPF_MODE(insn->code) == BPF_MEMSX) {
if (!bpf_jit_supports_insn(insn, true)) {
@@ -952,6 +934,29 @@ int bpf_convert_ctx_accesses(struct bpf_verifier_env *env)
env->prog->aux->num_exentries++;
continue;
default:
+ /*
+ * A pointer which may fault on a dereference must not
+ * be loaded from without fault protection, hence turn
+ * the BPF_LDX into a BPF_PROBE_MEM one so that a bad
+ * address is handled rather than panicking the kernel.
+ * A store through one is rejected earlier, there is no
+ * probed counterpart to rewrite it into.
+ */
+ if (bpf_is_ptr_to_mem_or_btf_id(ptr_type) &&
+ bpf_may_fault_on_deref(ptr_type) &&
+ type == BPF_READ) {
+ if (BPF_MODE(insn->code) == BPF_MEM)
+ insn->code = BPF_LDX | BPF_PROBE_MEM |
+ BPF_SIZE(insn->code);
+ else
+ insn->code = BPF_LDX | BPF_PROBE_MEMSX |
+ BPF_SIZE(insn->code);
+ env->prog->aux->num_exentries++;
+ continue;
+ }
+ if (verifier_bug_if(bpf_may_fault_on_deref(ptr_type), env,
+ "access to a fault prone pointer is not rewritten as a probed one"))
+ return -EFAULT;
continue;
}
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 6610e2437047..6fff370749bf 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -16999,17 +16999,6 @@ static bool reg_type_mismatch(enum bpf_reg_type src, enum bpf_reg_type prev)
!reg_type_mismatch_ok(prev));
}
-static bool is_ptr_to_mem_or_btf_id(enum bpf_reg_type type)
-{
- switch (base_type(type)) {
- case PTR_TO_MEM:
- case PTR_TO_BTF_ID:
- return true;
- default:
- return false;
- }
-}
-
static bool is_ptr_to_mem(enum bpf_reg_type type)
{
return base_type(type) == PTR_TO_MEM;
@@ -17049,8 +17038,8 @@ static int save_aux_ptr_type(struct bpf_verifier_env *env, enum bpf_reg_type typ
* Reject it.
*/
if (allow_trust_mismatch &&
- is_ptr_to_mem_or_btf_id(type) &&
- is_ptr_to_mem_or_btf_id(*prev_type)) {
+ bpf_is_ptr_to_mem_or_btf_id(type) &&
+ bpf_is_ptr_to_mem_or_btf_id(*prev_type)) {
/*
* Have to support a use case when one path through
* the program yields a TRUSTED pointer while another
--
2.43.0
next prev parent reply other threads:[~2026-08-14 21:53 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-14 21:52 [PATCH bpf-next v2 1/6] bpf: Keep fault protection when merging pointer types Daniel Borkmann
2026-08-14 21:52 ` [PATCH bpf-next v2 2/6] bpf: Treat a fault prone PTR_TO_MEM as a pointer type mismatch Daniel Borkmann
2026-08-16 19:44 ` Eduard Zingerman
2026-08-14 21:52 ` [PATCH bpf-next v2 3/6] bpf: Reject a store through a fault prone pointer Daniel Borkmann
2026-08-14 22:40 ` bot+bpf-ci
2026-08-14 23:26 ` Daniel Borkmann
2026-08-16 19:54 ` Eduard Zingerman
2026-08-16 20:02 ` Eduard Zingerman
2026-08-14 21:52 ` Daniel Borkmann [this message]
2026-08-16 20:06 ` [PATCH bpf-next v2 4/6] bpf: Rewrite any fault prone load out of a mem or btf_id pointer Eduard Zingerman
2026-08-14 21:52 ` [PATCH bpf-next v2 5/6] selftests/bpf: Add tests for pointer type merge at a shared load Daniel Borkmann
2026-08-14 22:56 ` bot+bpf-ci
2026-08-14 23:35 ` Daniel Borkmann
2026-08-16 22:24 ` Eduard Zingerman
2026-08-16 22:32 ` Eduard Zingerman
2026-08-17 8:08 ` Daniel Borkmann
2026-08-14 21:53 ` [PATCH bpf-next v2 6/6] selftests/bpf: Add tests for fault prone loads out of RCU pointers Daniel Borkmann
2026-08-14 22:03 ` sashiko-bot
2026-08-14 22:28 ` Daniel Borkmann
2026-08-16 22:24 ` Eduard Zingerman
2026-08-14 22:15 ` [PATCH bpf-next v2 1/6] bpf: Keep fault protection when merging pointer types sashiko-bot
2026-08-14 22:19 ` Daniel Borkmann
2026-08-16 19:42 ` Eduard Zingerman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260814215301.709827-4-daniel@iogearbox.net \
--to=daniel@iogearbox.net \
--cc=bpf@vger.kernel.org \
--cc=eddyz87@gmail.com \
--cc=memxor@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.