The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH bpf-next 0/2] bpf: Preserve RCU pointer nullness after unlock
@ 2026-06-20 15:17 Yiyang Chen
  2026-06-20 15:17 ` [PATCH bpf-next 1/2] bpf: Preserve nullable RCU pointer state on unlock Yiyang Chen
  2026-06-20 15:17 ` [PATCH bpf-next 2/2] selftests/bpf: Cover nullable RCU pointer use after unlock Yiyang Chen
  0 siblings, 2 replies; 4+ messages in thread
From: Yiyang Chen @ 2026-06-20 15:17 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi
  Cc: Yiyang Chen, John Fastabend, Martin KaFai Lau, Song Liu,
	Yonghong Song, Jiri Olsa, Emil Tsalapatis, Shuah Khan, bpf,
	linux-kselftest, linux-kernel

bpf_rcu_read_unlock() converts MEM_RCU verifier registers to
PTR_UNTRUSTED, but currently clears PTR_MAYBE_NULL at the same time.

That loses the nullable state for BTF_TYPE_SAFE_RCU_OR_NULL fields such as
skb->sk. A program can read skb->sk while in an RCU read-side critical
section, unlock RCU, and then dereference the pointer directly without the
verifier requiring an explicit NULL check.

Patch 1 preserves PTR_MAYBE_NULL when removing MEM_RCU.
Patch 2 adds a focused regression test for the unchecked dereference and a
matched null-checked control.

Yiyang Chen (2):
  bpf: Preserve nullable RCU pointer state on unlock
  selftests/bpf: Cover nullable RCU pointer use after unlock

 kernel/bpf/verifier.c                         |  2 +-
 .../selftests/bpf/prog_tests/rcu_read_lock.c  | 17 ++++++++++++++++
 .../selftests/bpf/progs/rcu_read_lock.c       | 20 +++++++++++++++++++
 3 files changed, 38 insertions(+), 1 deletion(-)


base-commit: a975094bf98ca97be9146f9d3b5681a6f9cf5ce3
-- 
2.34.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH bpf-next 1/2] bpf: Preserve nullable RCU pointer state on unlock
  2026-06-20 15:17 [PATCH bpf-next 0/2] bpf: Preserve RCU pointer nullness after unlock Yiyang Chen
@ 2026-06-20 15:17 ` Yiyang Chen
  2026-06-20 17:44   ` Alexei Starovoitov
  2026-06-20 15:17 ` [PATCH bpf-next 2/2] selftests/bpf: Cover nullable RCU pointer use after unlock Yiyang Chen
  1 sibling, 1 reply; 4+ messages in thread
From: Yiyang Chen @ 2026-06-20 15:17 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi
  Cc: Yiyang Chen, John Fastabend, Martin KaFai Lau, Song Liu,
	Yonghong Song, Jiri Olsa, Emil Tsalapatis, Shuah Khan, bpf,
	linux-kselftest, linux-kernel

bpf_rcu_read_unlock() converts RCU-protected verifier registers to
untrusted pointers so that programs cannot keep using RCU-trusted
references after the read-side critical section ends.

That conversion also clears PTR_MAYBE_NULL. For fields from the
BTF_TYPE_SAFE_RCU_OR_NULL allowlist, such as skb->sk, the verifier records
MEM_RCU | PTR_MAYBE_NULL while inside the RCU read-side critical section.
Clearing both flags on unlock drops the nullable state and allows a direct
post-unlock BTF member load without an explicit NULL check.

Only clear MEM_RCU during RCU unlock invalidation. Preserve PTR_MAYBE_NULL
so normal nullable-pointer checks reject direct access, while an explicit
NULL check can still refine the pointer before use.

Fixes: 30ee9821f943 ("bpf: Allowlist few fields similar to __rcu tag.")
Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
---
 kernel/bpf/verifier.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 2abc79dbf..e53c4bfe4 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -9001,7 +9001,7 @@ static void invalidate_rcu_protected_refs(struct bpf_verifier_env *env)
 
 	bpf_for_each_reg_in_vstate_mask(env->cur_state, state, reg, stack, clear_mask, ({
 		if (reg->type & MEM_RCU) {
-			reg->type &= ~(MEM_RCU | PTR_MAYBE_NULL);
+			reg->type &= ~MEM_RCU;
 			reg->type |= PTR_UNTRUSTED;
 		}
 	}));
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH bpf-next 2/2] selftests/bpf: Cover nullable RCU pointer use after unlock
  2026-06-20 15:17 [PATCH bpf-next 0/2] bpf: Preserve RCU pointer nullness after unlock Yiyang Chen
  2026-06-20 15:17 ` [PATCH bpf-next 1/2] bpf: Preserve nullable RCU pointer state on unlock Yiyang Chen
@ 2026-06-20 15:17 ` Yiyang Chen
  1 sibling, 0 replies; 4+ messages in thread
From: Yiyang Chen @ 2026-06-20 15:17 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi
  Cc: Yiyang Chen, John Fastabend, Martin KaFai Lau, Song Liu,
	Yonghong Song, Jiri Olsa, Emil Tsalapatis, Shuah Khan, bpf,
	linux-kselftest, linux-kernel

Add coverage for nullable BTF pointers that are read under
bpf_rcu_read_lock() and then used after bpf_rcu_read_unlock().

The unchecked skb->sk dereference should be rejected because the pointer
can still be NULL after it loses MEM_RCU trust. The matched control
performs an explicit NULL check after unlock and should keep loading
successfully.

Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
---
 .../selftests/bpf/prog_tests/rcu_read_lock.c  | 17 ++++++++++++++++
 .../selftests/bpf/progs/rcu_read_lock.c       | 20 +++++++++++++++++++
 2 files changed, 37 insertions(+)

diff --git a/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c b/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c
index 246eb259c..be0317a47 100644
--- a/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c
+++ b/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c
@@ -72,6 +72,20 @@ static void test_rcuptr_acquire(void)
 	rcu_read_lock__destroy(skel);
 }
 
+static void test_rcuptr_null_check(void)
+{
+	struct rcu_read_lock *skel;
+
+	skel = rcu_read_lock__open();
+	if (!ASSERT_OK_PTR(skel, "skel_open"))
+		return;
+
+	bpf_program__set_autoload(skel->progs.rcu_null_check_after_unlock, true);
+	ASSERT_OK(rcu_read_lock__load(skel), "skel_load");
+
+	rcu_read_lock__destroy(skel);
+}
+
 static const char * const inproper_region_tests[] = {
 	"miss_lock",
 	"no_lock",
@@ -113,6 +127,7 @@ static void test_inproper_region(void)
 static const char * const rcuptr_misuse_tests[] = {
 	"task_untrusted_rcuptr",
 	"cross_rcu_region",
+	"rcu_null_deref_after_unlock",
 };
 
 static void test_rcuptr_misuse(void)
@@ -150,6 +165,8 @@ void test_rcu_read_lock(void)
 		test_success();
 	if (test__start_subtest("rcuptr_acquire"))
 		test_rcuptr_acquire();
+	if (test__start_subtest("rcuptr_null_check"))
+		test_rcuptr_null_check();
 	if (test__start_subtest("negative_tests_inproper_region"))
 		test_inproper_region();
 	if (test__start_subtest("negative_tests_rcuptr_misuse"))
diff --git a/tools/testing/selftests/bpf/progs/rcu_read_lock.c b/tools/testing/selftests/bpf/progs/rcu_read_lock.c
index b4e073168..b78542706 100644
--- a/tools/testing/selftests/bpf/progs/rcu_read_lock.c
+++ b/tools/testing/selftests/bpf/progs/rcu_read_lock.c
@@ -372,6 +372,26 @@ int cross_rcu_region(void *ctx)
 	return 0;
 }
 
+SEC("?tp_btf/net_dev_queue")
+int BPF_PROG(rcu_null_check_after_unlock, struct sk_buff *skb)
+{
+	bpf_rcu_read_lock();
+	bpf_rcu_read_unlock();
+
+	if (!skb->sk)
+		return 0;
+	return skb->sk->__sk_common.skc_daddr;
+}
+
+SEC("?tp_btf/net_dev_queue")
+int BPF_PROG(rcu_null_deref_after_unlock, struct sk_buff *skb)
+{
+	bpf_rcu_read_lock();
+	bpf_rcu_read_unlock();
+
+	return skb->sk->__sk_common.skc_daddr;
+}
+
 __noinline
 static int static_subprog(void *ctx)
 {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH bpf-next 1/2] bpf: Preserve nullable RCU pointer state on unlock
  2026-06-20 15:17 ` [PATCH bpf-next 1/2] bpf: Preserve nullable RCU pointer state on unlock Yiyang Chen
@ 2026-06-20 17:44   ` Alexei Starovoitov
  0 siblings, 0 replies; 4+ messages in thread
From: Alexei Starovoitov @ 2026-06-20 17:44 UTC (permalink / raw)
  To: Yiyang Chen, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi
  Cc: John Fastabend, Martin KaFai Lau, Song Liu, Yonghong Song,
	Jiri Olsa, Emil Tsalapatis, Shuah Khan, bpf, linux-kselftest,
	linux-kernel

On Sat Jun 20, 2026 at 8:17 AM PDT, Yiyang Chen wrote:
> bpf_rcu_read_unlock() converts RCU-protected verifier registers to
> untrusted pointers so that programs cannot keep using RCU-trusted
> references after the read-side critical section ends.
>
> That conversion also clears PTR_MAYBE_NULL. For fields from the
> BTF_TYPE_SAFE_RCU_OR_NULL allowlist, such as skb->sk, the verifier records
> MEM_RCU | PTR_MAYBE_NULL while inside the RCU read-side critical section.
> Clearing both flags on unlock drops the nullable state and allows a direct
> post-unlock BTF member load without an explicit NULL check.

That's exactly the point. The code works as designed.

> Only clear MEM_RCU during RCU unlock invalidation. Preserve PTR_MAYBE_NULL
> so normal nullable-pointer checks reject direct access, while an explicit
> NULL check can still refine the pointer before use.
>
> Fixes: 30ee9821f943 ("bpf: Allowlist few fields similar to __rcu tag.")

Nothing to fix.

pw-bot: cr

> Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
> ---
>  kernel/bpf/verifier.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 2abc79dbf..e53c4bfe4 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -9001,7 +9001,7 @@ static void invalidate_rcu_protected_refs(struct bpf_verifier_env *env)
>  
>  	bpf_for_each_reg_in_vstate_mask(env->cur_state, state, reg, stack, clear_mask, ({
>  		if (reg->type & MEM_RCU) {
> -			reg->type &= ~(MEM_RCU | PTR_MAYBE_NULL);
> +			reg->type &= ~MEM_RCU;
>  			reg->type |= PTR_UNTRUSTED;
>  		}
>  	}));


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-06-20 17:44 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-20 15:17 [PATCH bpf-next 0/2] bpf: Preserve RCU pointer nullness after unlock Yiyang Chen
2026-06-20 15:17 ` [PATCH bpf-next 1/2] bpf: Preserve nullable RCU pointer state on unlock Yiyang Chen
2026-06-20 17:44   ` Alexei Starovoitov
2026-06-20 15:17 ` [PATCH bpf-next 2/2] selftests/bpf: Cover nullable RCU pointer use after unlock Yiyang Chen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox