From: Ning Ding <dingning04@gmail.com>
To: bpf@vger.kernel.org
Cc: ast@kernel.org, daniel@iogearbox.net, john.fastabend@gmail.com,
andrii@kernel.org, eddyz87@gmail.com, memxor@gmail.com,
martin.lau@linux.dev, song@kernel.org, yonghong.song@linux.dev,
jolsa@kernel.org, emil@etsalapatis.com, shuah@kernel.org,
danieltimlee@gmail.com, linux-kernel@vger.kernel.org,
linux-kselftest@vger.kernel.org, Ning Ding <dingning04@gmail.com>
Subject: [PATCH bpf] bpf: Reject writes through untrusted allocated pointers
Date: Mon, 27 Jul 2026 20:38:37 -0700 [thread overview]
Message-ID: <20260728033837.1466123-1-dingning04@gmail.com> (raw)
In-Reply-To: <20260726021304.97ED91F000E9@smtp.kernel.org>
A kptr loaded under an RCU read lock has MEM_ALLOC set. After
bpf_rcu_read_unlock(), the verifier marks it PTR_UNTRUSTED, but
check_ptr_to_btf_access() still allows writes because
type_is_ptr_alloc_obj() ignores that flag.
Reject writes through MEM_ALLOC pointers that are PTR_UNTRUSTED. Reads
remain allowed and are converted to probe-memory accesses.
Also skip the owning-reference check for these pointers, since they no
longer have a live reference after leaving the RCU critical section.
Add verifier tests for the rejected write and permitted read cases.
Fixes: 503e4def5414 ("bpf: Replace open code with for allocated object check")
Closes: https://lore.kernel.org/all/20260726021304.97ED91F000E9@smtp.kernel.org/
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Ning Ding <dingning04@gmail.com>
---
kernel/bpf/verifier.c | 6 +-
.../bpf/progs/local_kptr_stash_fail.c | 58 +++++++++++++++++++
2 files changed, 62 insertions(+), 2 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 7aa47342dc65..24c151ad2e62 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -5804,13 +5804,15 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
* program allocated objects (which always have id > 0),
* but not for untrusted PTR_TO_BTF_ID | MEM_ALLOC.
*/
- if (atype != BPF_READ && !type_is_ptr_alloc_obj(reg->type)) {
+ if (atype != BPF_READ &&
+ (!type_is_ptr_alloc_obj(reg->type) || reg->type & PTR_UNTRUSTED)) {
verbose(env, "only read is supported\n");
return -EACCES;
}
if (type_is_alloc(reg->type) && !type_is_non_owning_ref(reg->type) &&
- !(reg->type & MEM_RCU) && !reg_is_referenced(env, reg)) {
+ !(reg->type & (MEM_RCU | PTR_UNTRUSTED)) &&
+ !reg_is_referenced(env, reg)) {
verifier_bug(env, "allocated object must have a referenced id");
return -EFAULT;
}
diff --git a/tools/testing/selftests/bpf/progs/local_kptr_stash_fail.c b/tools/testing/selftests/bpf/progs/local_kptr_stash_fail.c
index fcf7a7567da2..d7b8cd6458bb 100644
--- a/tools/testing/selftests/bpf/progs/local_kptr_stash_fail.c
+++ b/tools/testing/selftests/bpf/progs/local_kptr_stash_fail.c
@@ -8,14 +8,22 @@
#include "../bpf_experimental.h"
#include "bpf_misc.h"
+extern void bpf_rcu_read_lock(void) __ksym;
+extern void bpf_rcu_read_unlock(void) __ksym;
+
struct node_data {
long key;
long data;
struct bpf_rb_node node;
};
+struct plain_data {
+ long key;
+};
+
struct map_value {
struct node_data __kptr *node;
+ struct plain_data __kptr *plain;
};
struct node_data2 {
@@ -31,6 +39,7 @@ struct node_data2 {
* [35] TYPE_TAG 'kptr_ref' type_id=34
*/
struct node_data *just_here_because_btf_bug;
+struct plain_data *just_here_because_btf_bug2;
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
@@ -82,4 +91,53 @@ long drop_rb_node_off(void *ctx)
return 0;
}
+SEC("?tc")
+__failure __msg("only read is supported")
+long write_untrusted_alloc_obj(void *ctx)
+{
+ struct map_value *mapval;
+ struct node_data *res;
+ int idx = 0;
+
+ mapval = bpf_map_lookup_elem(&some_nodes, &idx);
+ if (!mapval)
+ return 1;
+
+ bpf_rcu_read_lock();
+ res = mapval->node;
+ if (!res) {
+ bpf_rcu_read_unlock();
+ return 2;
+ }
+ barrier_var(res);
+ bpf_rcu_read_unlock();
+
+ res->key = 42;
+ return 0;
+}
+
+SEC("?tc")
+__success
+long read_untrusted_alloc_obj(void *ctx)
+{
+ struct map_value *mapval;
+ struct plain_data *res;
+ int idx = 0;
+
+ mapval = bpf_map_lookup_elem(&some_nodes, &idx);
+ if (!mapval)
+ return 1;
+
+ bpf_rcu_read_lock();
+ res = mapval->plain;
+ if (!res) {
+ bpf_rcu_read_unlock();
+ return 2;
+ }
+ barrier_var(res);
+ bpf_rcu_read_unlock();
+
+ return res->key;
+}
+
char _license[] SEC("license") = "GPL";
--
2.43.0
prev parent reply other threads:[~2026-07-28 3:38 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-26 1:53 [PATCH bpf] bpf: Keep refcount_acquire nullable for borrowed RCU kptrs Ning Ding
2026-07-26 2:13 ` sashiko-bot
2026-07-28 3:38 ` Ning Ding [this message]
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=20260728033837.1466123-1-dingning04@gmail.com \
--to=dingning04@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=danieltimlee@gmail.com \
--cc=eddyz87@gmail.com \
--cc=emil@etsalapatis.com \
--cc=john.fastabend@gmail.com \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=martin.lau@linux.dev \
--cc=memxor@gmail.com \
--cc=shuah@kernel.org \
--cc=song@kernel.org \
--cc=yonghong.song@linux.dev \
/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.