BPF List
 help / color / mirror / Atom feed
* [PATCH bpf-next 1/2] bpf: Check load-acquire src ptr type before the load
@ 2026-08-04 20:19 Daniel Borkmann
  2026-08-04 20:19 ` [PATCH bpf-next 2/2] selftests/bpf: Add load-acquire test for dst_reg == src_reg from ctx Daniel Borkmann
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Daniel Borkmann @ 2026-08-04 20:19 UTC (permalink / raw)
  To: memxor; +Cc: eddyz87, puranjay, info, bpf

check_atomic_load() calls check_load_mem() before atomic_ptr_type_ok().
For a load-acquire that fetches into its own source register (dst_reg ==
src_reg), check_load_mem() overwrites src_reg's type with the type of the
loaded value, so the subsequent atomic_ptr_type_ok() no longer sees the
source pointer and fails to reject the disallowed types (ctx, pkt,
flow_keys, sock).

Since bpf_convert_ctx_accesses() does not rewrite atomic loads, the raw
access to the underlying kernel object is left in place. The destination
type is taken from the ctx access itself, so a load-acquire of the sk
field of struct __sk_buff for example leaves the register typed as
PTR_TO_SOCK_COMMON_OR_NULL, which type_is_sk_pointer() does not match
either, while it actually holds unconverted struct sk_buff bytes. Once
the NULL check has passed this is a type confusion, not just a leak of
kernel data.

Validate src_reg with check_reg_arg() and check the source pointer type
with atomic_ptr_type_ok() before the load again, mirroring
check_atomic_rmw(). Out-of-range register numbers are already rejected
earlier by check_and_resolve_insns() (commit 503d21ef8eac ("bpf: Do
register range validation early")), and the only exemption there,
is_stack_arg_ldx(), requires BPF_LDX | BPF_MEM | BPF_DW and thus never
matches a BPF_ATOMIC insn. atomic_ptr_type_ok() can therefore not
dereference register state out of bounds, that is, the out-of-bounds
read addressed by the Fixes commit below does not reappear (as proven
also via selftest).

Fixes: c03bb2fa327e ("bpf: Fix out-of-bounds read in check_atomic_load/store()")
Reported-by: STAR Labs SG <info@starlabs.sg>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
 kernel/bpf/verifier.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index b274004fccfd..9513e18836c2 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -6616,7 +6616,7 @@ static int check_atomic_load(struct bpf_verifier_env *env,
 {
 	int err;
 
-	err = check_load_mem(env, insn, true, false, false, "atomic_load");
+	err = check_reg_arg(env, insn->src_reg, SRC_OP);
 	if (err)
 		return err;
 
@@ -6627,7 +6627,7 @@ static int check_atomic_load(struct bpf_verifier_env *env,
 		return -EACCES;
 	}
 
-	return 0;
+	return check_load_mem(env, insn, true, false, false, "atomic_load");
 }
 
 static int check_atomic_store(struct bpf_verifier_env *env,
-- 
2.43.0


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

* [PATCH bpf-next 2/2] selftests/bpf: Add load-acquire test for dst_reg == src_reg from ctx
  2026-08-04 20:19 [PATCH bpf-next 1/2] bpf: Check load-acquire src ptr type before the load Daniel Borkmann
@ 2026-08-04 20:19 ` Daniel Borkmann
  2026-08-05  9:23   ` Eduard Zingerman
  2026-08-05  9:22 ` [PATCH bpf-next 1/2] bpf: Check load-acquire src ptr type before the load Eduard Zingerman
  2026-08-05 10:10 ` patchwork-bot+netdevbpf
  2 siblings, 1 reply; 5+ messages in thread
From: Daniel Borkmann @ 2026-08-04 20:19 UTC (permalink / raw)
  To: memxor; +Cc: eddyz87, puranjay, info, bpf

Add a verifier test that a load-acquire fetching into its own source
register (dst_reg == src_reg) from a ctx pointer is rejected.

  # LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_load_acquire
  [...]
  #614/1   verifier_load_acquire/load-acquire, 8-bit:OK
  #614/2   verifier_load_acquire/load-acquire, 8-bit @unpriv:OK
  #614/3   verifier_load_acquire/load-acquire, 16-bit:OK
  #614/4   verifier_load_acquire/load-acquire, 16-bit @unpriv:OK
  #614/5   verifier_load_acquire/load-acquire, 32-bit:OK
  #614/6   verifier_load_acquire/load-acquire, 32-bit @unpriv:OK
  #614/7   verifier_load_acquire/load-acquire, 64-bit:OK
  #614/8   verifier_load_acquire/load-acquire, 64-bit @unpriv:OK
  #614/9   verifier_load_acquire/load-acquire with uninitialized src_reg:OK
  #614/10  verifier_load_acquire/load-acquire with uninitialized src_reg @unpriv:OK
  #614/11  verifier_load_acquire/load-acquire with non-pointer src_reg:OK
  #614/12  verifier_load_acquire/load-acquire with non-pointer src_reg @unpriv:OK
  #614/13  verifier_load_acquire/misaligned load-acquire:OK
  #614/14  verifier_load_acquire/misaligned load-acquire @unpriv:OK
  #614/15  verifier_load_acquire/load-acquire from ctx pointer:OK
  #614/16  verifier_load_acquire/load-acquire from ctx pointer @unpriv:OK
  #614/17  verifier_load_acquire/load-acquire from ctx pointer, same dst and src register:OK
  #614/18  verifier_load_acquire/load-acquire from ctx pointer, same dst and src register @unpriv:OK
  #614/19  verifier_load_acquire/load-acquire with invalid register R15:OK
  #614/20  verifier_load_acquire/load-acquire with invalid register R15 @unpriv:OK
  #614/21  verifier_load_acquire/load-acquire from pkt pointer:OK
  #614/22  verifier_load_acquire/load-acquire from flow_keys pointer:OK
  #614/23  verifier_load_acquire/load-acquire from sock pointer:OK
  #614     verifier_load_acquire:OK
  Summary: 1/23 PASSED, 0 SKIPPED, 0 FAILED

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
 .../selftests/bpf/progs/verifier_load_acquire.c  | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/tools/testing/selftests/bpf/progs/verifier_load_acquire.c b/tools/testing/selftests/bpf/progs/verifier_load_acquire.c
index 74f4f19c10b8..ae1dab1b0cbb 100644
--- a/tools/testing/selftests/bpf/progs/verifier_load_acquire.c
+++ b/tools/testing/selftests/bpf/progs/verifier_load_acquire.c
@@ -148,6 +148,22 @@ __naked void load_acquire_from_ctx_pointer(void)
 	: __clobber_all);
 }
 
+SEC("socket")
+__description("load-acquire from ctx pointer, same dst and src register")
+__failure __failure_unpriv __msg("BPF_ATOMIC loads from R6 ctx is not allowed")
+__naked void load_acquire_ctx_same_dst_src(void)
+{
+	asm volatile (
+	"r6 = r1;"
+	".8byte %[load_acquire_insn];"	// w6 = load_acquire((u32 *)(r6 + 0));
+	"r0 = 0;"
+	"exit;"
+	:
+	: __imm_insn(load_acquire_insn,
+		     BPF_ATOMIC_OP(BPF_W, BPF_LOAD_ACQ, BPF_REG_6, BPF_REG_6, 0))
+	: __clobber_all);
+}
+
 SEC("xdp")
 __description("load-acquire from pkt pointer")
 __failure __msg("BPF_ATOMIC loads from R2 pkt is not allowed")
-- 
2.43.0


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

* Re: [PATCH bpf-next 1/2] bpf: Check load-acquire src ptr type before the load
  2026-08-04 20:19 [PATCH bpf-next 1/2] bpf: Check load-acquire src ptr type before the load Daniel Borkmann
  2026-08-04 20:19 ` [PATCH bpf-next 2/2] selftests/bpf: Add load-acquire test for dst_reg == src_reg from ctx Daniel Borkmann
@ 2026-08-05  9:22 ` Eduard Zingerman
  2026-08-05 10:10 ` patchwork-bot+netdevbpf
  2 siblings, 0 replies; 5+ messages in thread
From: Eduard Zingerman @ 2026-08-05  9:22 UTC (permalink / raw)
  To: Daniel Borkmann, memxor; +Cc: puranjay, info, bpf

On Tue, 2026-08-04 at 22:19 +0200, Daniel Borkmann wrote:
> check_atomic_load() calls check_load_mem() before atomic_ptr_type_ok().
> For a load-acquire that fetches into its own source register (dst_reg ==
> src_reg), check_load_mem() overwrites src_reg's type with the type of the
> loaded value, so the subsequent atomic_ptr_type_ok() no longer sees the
> source pointer and fails to reject the disallowed types (ctx, pkt,
> flow_keys, sock).
> 
> Since bpf_convert_ctx_accesses() does not rewrite atomic loads, the raw
> access to the underlying kernel object is left in place. The destination
> type is taken from the ctx access itself, so a load-acquire of the sk
> field of struct __sk_buff for example leaves the register typed as
> PTR_TO_SOCK_COMMON_OR_NULL, which type_is_sk_pointer() does not match
> either, while it actually holds unconverted struct sk_buff bytes. Once
> the NULL check has passed this is a type confusion, not just a leak of
> kernel data.
> 
> Validate src_reg with check_reg_arg() and check the source pointer type
> with atomic_ptr_type_ok() before the load again, mirroring
> check_atomic_rmw(). Out-of-range register numbers are already rejected
> earlier by check_and_resolve_insns() (commit 503d21ef8eac ("bpf: Do
> register range validation early")), and the only exemption there,
> is_stack_arg_ldx(), requires BPF_LDX | BPF_MEM | BPF_DW and thus never
> matches a BPF_ATOMIC insn. atomic_ptr_type_ok() can therefore not
> dereference register state out of bounds, that is, the out-of-bounds
> read addressed by the Fixes commit below does not reappear (as proven
> also via selftest).
> 
> Fixes: c03bb2fa327e ("bpf: Fix out-of-bounds read in check_atomic_load/store()")
> Reported-by: STAR Labs SG <info@starlabs.sg>
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
> ---

Acked-by: Eduard Zingerman <eddyz87@gmail.com>

...

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

* Re: [PATCH bpf-next 2/2] selftests/bpf: Add load-acquire test for dst_reg == src_reg from ctx
  2026-08-04 20:19 ` [PATCH bpf-next 2/2] selftests/bpf: Add load-acquire test for dst_reg == src_reg from ctx Daniel Borkmann
@ 2026-08-05  9:23   ` Eduard Zingerman
  0 siblings, 0 replies; 5+ messages in thread
From: Eduard Zingerman @ 2026-08-05  9:23 UTC (permalink / raw)
  To: Daniel Borkmann, memxor; +Cc: puranjay, info, bpf

On Tue, 2026-08-04 at 22:19 +0200, Daniel Borkmann wrote:
> Add a verifier test that a load-acquire fetching into its own source
> register (dst_reg == src_reg) from a ctx pointer is rejected.
> 
>   # LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_load_acquire
>   [...]
>   #614/1   verifier_load_acquire/load-acquire, 8-bit:OK
>   #614/2   verifier_load_acquire/load-acquire, 8-bit @unpriv:OK
>   #614/3   verifier_load_acquire/load-acquire, 16-bit:OK
>   #614/4   verifier_load_acquire/load-acquire, 16-bit @unpriv:OK
>   #614/5   verifier_load_acquire/load-acquire, 32-bit:OK
>   #614/6   verifier_load_acquire/load-acquire, 32-bit @unpriv:OK
>   #614/7   verifier_load_acquire/load-acquire, 64-bit:OK
>   #614/8   verifier_load_acquire/load-acquire, 64-bit @unpriv:OK
>   #614/9   verifier_load_acquire/load-acquire with uninitialized src_reg:OK
>   #614/10  verifier_load_acquire/load-acquire with uninitialized src_reg @unpriv:OK
>   #614/11  verifier_load_acquire/load-acquire with non-pointer src_reg:OK
>   #614/12  verifier_load_acquire/load-acquire with non-pointer src_reg @unpriv:OK
>   #614/13  verifier_load_acquire/misaligned load-acquire:OK
>   #614/14  verifier_load_acquire/misaligned load-acquire @unpriv:OK
>   #614/15  verifier_load_acquire/load-acquire from ctx pointer:OK
>   #614/16  verifier_load_acquire/load-acquire from ctx pointer @unpriv:OK
>   #614/17  verifier_load_acquire/load-acquire from ctx pointer, same dst and src register:OK
>   #614/18  verifier_load_acquire/load-acquire from ctx pointer, same dst and src register @unpriv:OK
>   #614/19  verifier_load_acquire/load-acquire with invalid register R15:OK
>   #614/20  verifier_load_acquire/load-acquire with invalid register R15 @unpriv:OK
>   #614/21  verifier_load_acquire/load-acquire from pkt pointer:OK
>   #614/22  verifier_load_acquire/load-acquire from flow_keys pointer:OK
>   #614/23  verifier_load_acquire/load-acquire from sock pointer:OK
>   #614     verifier_load_acquire:OK
>   Summary: 1/23 PASSED, 0 SKIPPED, 0 FAILED
> 
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
> ---

Acked-by: Eduard Zingerman <eddyz87@gmail.com>

...

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

* Re: [PATCH bpf-next 1/2] bpf: Check load-acquire src ptr type before the load
  2026-08-04 20:19 [PATCH bpf-next 1/2] bpf: Check load-acquire src ptr type before the load Daniel Borkmann
  2026-08-04 20:19 ` [PATCH bpf-next 2/2] selftests/bpf: Add load-acquire test for dst_reg == src_reg from ctx Daniel Borkmann
  2026-08-05  9:22 ` [PATCH bpf-next 1/2] bpf: Check load-acquire src ptr type before the load Eduard Zingerman
@ 2026-08-05 10:10 ` patchwork-bot+netdevbpf
  2 siblings, 0 replies; 5+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-08-05 10:10 UTC (permalink / raw)
  To: Daniel Borkmann; +Cc: memxor, eddyz87, puranjay, info, bpf

Hello:

This series was applied to bpf/bpf-next.git (master)
by Kumar Kartikeya Dwivedi <memxor@gmail.com>:

On Tue,  4 Aug 2026 22:19:16 +0200 you wrote:
> check_atomic_load() calls check_load_mem() before atomic_ptr_type_ok().
> For a load-acquire that fetches into its own source register (dst_reg ==
> src_reg), check_load_mem() overwrites src_reg's type with the type of the
> loaded value, so the subsequent atomic_ptr_type_ok() no longer sees the
> source pointer and fails to reject the disallowed types (ctx, pkt,
> flow_keys, sock).
> 
> [...]

Here is the summary with links:
  - [bpf-next,1/2] bpf: Check load-acquire src ptr type before the load
    https://git.kernel.org/bpf/bpf-next/c/b87803391baa
  - [bpf-next,2/2] selftests/bpf: Add load-acquire test for dst_reg == src_reg from ctx
    https://git.kernel.org/bpf/bpf-next/c/363b15d8551e

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



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

end of thread, other threads:[~2026-08-05 10:10 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-04 20:19 [PATCH bpf-next 1/2] bpf: Check load-acquire src ptr type before the load Daniel Borkmann
2026-08-04 20:19 ` [PATCH bpf-next 2/2] selftests/bpf: Add load-acquire test for dst_reg == src_reg from ctx Daniel Borkmann
2026-08-05  9:23   ` Eduard Zingerman
2026-08-05  9:22 ` [PATCH bpf-next 1/2] bpf: Check load-acquire src ptr type before the load Eduard Zingerman
2026-08-05 10:10 ` patchwork-bot+netdevbpf

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