* [PATCH bpf-next 1/2] bpf: Drop pkt_end markers on arithmetic to prevent is_pkt_ptr_branch_taken
@ 2026-04-09 15:50 Daniel Borkmann
2026-04-09 15:50 ` [PATCH bpf-next 2/2] selftests/bpf: Add test for stale pkt range after scalar arithmetic Daniel Borkmann
2026-04-09 20:20 ` [PATCH bpf-next 1/2] bpf: Drop pkt_end markers on arithmetic to prevent is_pkt_ptr_branch_taken patchwork-bot+netdevbpf
0 siblings, 2 replies; 3+ messages in thread
From: Daniel Borkmann @ 2026-04-09 15:50 UTC (permalink / raw)
To: bpf; +Cc: ast, eddyz87, info
When a pkt pointer acquires AT_PKT_END or BEYOND_PKT_END range from
a comparison, and then, known-constant arithmetic is performed,
adjust_ptr_min_max_vals() copies the stale range via dst_reg->raw =
ptr_reg->raw without clearing the negative reg->range sentinel values.
This lets is_pkt_ptr_branch_taken() choose one branch direction and
skip going through the other. Fix this by clearing negative pkt range
values (that is, AT_PKT_END and BEYOND_PKT_END) after arithmetic on
pkt pointers. This ensures is_pkt_ptr_branch_taken() returns unknown
and both branches are properly verified.
Fixes: 6d94e741a8ff ("bpf: Support for pointers beyond pkt_end.")
Reported-by: STAR Labs SG <info@starlabs.sg>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
kernel/bpf/verifier.c | 30 ++++++++++++++++++++++--------
1 file changed, 22 insertions(+), 8 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 1227b168bb07..9c1135d373e2 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -15448,10 +15448,17 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
}
dst_reg->var_off = tnum_add(ptr_reg->var_off, off_reg->var_off);
dst_reg->raw = ptr_reg->raw;
- if (!known && reg_is_pkt_pointer(ptr_reg)) {
- dst_reg->id = ++env->id_gen;
- /* something was added to pkt_ptr, set range to zero */
- memset(&dst_reg->raw, 0, sizeof(dst_reg->raw));
+ if (reg_is_pkt_pointer(ptr_reg)) {
+ if (!known)
+ dst_reg->id = ++env->id_gen;
+ /*
+ * Clear range for unknown addends since we can't know
+ * where the pkt pointer ended up. Also clear AT_PKT_END /
+ * BEYOND_PKT_END from prior comparison as any pointer
+ * arithmetic invalidates them.
+ */
+ if (!known || dst_reg->range < 0)
+ memset(&dst_reg->raw, 0, sizeof(dst_reg->raw));
}
break;
case BPF_SUB:
@@ -15490,10 +15497,17 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
}
dst_reg->var_off = tnum_sub(ptr_reg->var_off, off_reg->var_off);
dst_reg->raw = ptr_reg->raw;
- if (!known && reg_is_pkt_pointer(ptr_reg)) {
- dst_reg->id = ++env->id_gen;
- /* something was added to pkt_ptr, set range to zero */
- if (smin_val < 0)
+ if (reg_is_pkt_pointer(ptr_reg)) {
+ if (!known)
+ dst_reg->id = ++env->id_gen;
+ /*
+ * Clear range if the subtrahend may be negative since
+ * pkt pointer could move past its bounds. A positive
+ * subtrahend moves it backwards keeping positive range
+ * intact. Also clear AT_PKT_END / BEYOND_PKT_END from
+ * prior comparison as arithmetic invalidates them.
+ */
+ if ((!known && smin_val < 0) || dst_reg->range < 0)
memset(&dst_reg->raw, 0, sizeof(dst_reg->raw));
}
break;
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* [PATCH bpf-next 2/2] selftests/bpf: Add test for stale pkt range after scalar arithmetic
2026-04-09 15:50 [PATCH bpf-next 1/2] bpf: Drop pkt_end markers on arithmetic to prevent is_pkt_ptr_branch_taken Daniel Borkmann
@ 2026-04-09 15:50 ` Daniel Borkmann
2026-04-09 20:20 ` [PATCH bpf-next 1/2] bpf: Drop pkt_end markers on arithmetic to prevent is_pkt_ptr_branch_taken patchwork-bot+netdevbpf
1 sibling, 0 replies; 3+ messages in thread
From: Daniel Borkmann @ 2026-04-09 15:50 UTC (permalink / raw)
To: bpf; +Cc: ast, eddyz87, info
Extend the verifier_direct_packet_access BPF selftests to exercise the
verifier code paths which ensure that the pkt range is cleared after
add/sub alu with a known scalar. The tests reject the invalid access.
# LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_direct
[...]
#592/35 verifier_direct_packet_access/direct packet access: pkt_range cleared after sub with known scalar:OK
#592/36 verifier_direct_packet_access/direct packet access: pkt_range cleared after add with known scalar:OK
#592/37 verifier_direct_packet_access/direct packet access: test3:OK
#592/38 verifier_direct_packet_access/direct packet access: test3 @unpriv:OK
#592/39 verifier_direct_packet_access/direct packet access: test34 (non-linear, cgroup_skb/ingress, too short eth):OK
#592/40 verifier_direct_packet_access/direct packet access: test35 (non-linear, cgroup_skb/ingress, too short 1):OK
#592/41 verifier_direct_packet_access/direct packet access: test36 (non-linear, cgroup_skb/ingress, long enough):OK
#592 verifier_direct_packet_access:OK
[...]
Summary: 2/47 PASSED, 0 SKIPPED, 0 FAILED
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
.../bpf/progs/verifier_direct_packet_access.c | 61 +++++++++++++++++++
1 file changed, 61 insertions(+)
diff --git a/tools/testing/selftests/bpf/progs/verifier_direct_packet_access.c b/tools/testing/selftests/bpf/progs/verifier_direct_packet_access.c
index 4ee3b7a708f7..915a9707298b 100644
--- a/tools/testing/selftests/bpf/progs/verifier_direct_packet_access.c
+++ b/tools/testing/selftests/bpf/progs/verifier_direct_packet_access.c
@@ -859,4 +859,65 @@ l0_%=: r0 = 1; \
: __clobber_all);
}
+SEC("tc")
+__description("direct packet access: pkt_range cleared after sub with known scalar")
+__failure __msg("invalid access to packet")
+__naked void pkt_range_clear_after_sub(void)
+{
+ asm volatile (" \
+ r9 = *(u32*)(r1 + %[__sk_buff_data]); \
+ r8 = *(u32*)(r1 + %[__sk_buff_data_end]); \
+ r9 += 256; \
+ if r9 >= r8 goto l0_%=; \
+ r0 = 0; \
+ exit; \
+l0_%=: /* r9 has AT_PKT_END (pkt + 256 >= pkt_end) */ \
+ r9 -= 256; \
+ /* \
+ * AT_PKT_END must not survive the arithmetic. \
+ * is_pkt_ptr_branch_taken must validate both \
+ * branches when visiting the next condition. \
+ */ \
+ if r9 < r8 goto l1_%=; \
+ r0 = 0; \
+ exit; \
+l1_%=: r0 = *(u8*)(r9 + 0); \
+ r0 = 0; \
+ exit; \
+" :
+ : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
+ __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
+ : __clobber_all);
+}
+
+SEC("tc")
+__description("direct packet access: pkt_range cleared after add with known scalar")
+__failure __msg("invalid access to packet")
+__naked void pkt_range_clear_after_add(void)
+{
+ asm volatile (" \
+ r9 = *(u32*)(r1 + %[__sk_buff_data]); \
+ r8 = *(u32*)(r1 + %[__sk_buff_data_end]); \
+ r9 += 256; \
+ if r9 >= r8 goto l0_%=; \
+ r0 = 0; \
+ exit; \
+l0_%=: /* r9 has AT_PKT_END (pkt + 256 >= pkt_end) */ \
+ r9 += -256; \
+ /* \
+ * Same as sub, but goes through BPF_ADD path. \
+ * AT_PKT_END must not survive the arithmetic. \
+ */ \
+ if r9 < r8 goto l1_%=; \
+ r0 = 0; \
+ exit; \
+l1_%=: r0 = *(u8*)(r9 + 0); \
+ r0 = 0; \
+ exit; \
+" :
+ : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
+ __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
+ : __clobber_all);
+}
+
char _license[] SEC("license") = "GPL";
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH bpf-next 1/2] bpf: Drop pkt_end markers on arithmetic to prevent is_pkt_ptr_branch_taken
2026-04-09 15:50 [PATCH bpf-next 1/2] bpf: Drop pkt_end markers on arithmetic to prevent is_pkt_ptr_branch_taken Daniel Borkmann
2026-04-09 15:50 ` [PATCH bpf-next 2/2] selftests/bpf: Add test for stale pkt range after scalar arithmetic Daniel Borkmann
@ 2026-04-09 20:20 ` patchwork-bot+netdevbpf
1 sibling, 0 replies; 3+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-04-09 20:20 UTC (permalink / raw)
To: Daniel Borkmann; +Cc: bpf, ast, eddyz87, info
Hello:
This series was applied to bpf/bpf-next.git (master)
by Alexei Starovoitov <ast@kernel.org>:
On Thu, 9 Apr 2026 17:50:15 +0200 you wrote:
> When a pkt pointer acquires AT_PKT_END or BEYOND_PKT_END range from
> a comparison, and then, known-constant arithmetic is performed,
> adjust_ptr_min_max_vals() copies the stale range via dst_reg->raw =
> ptr_reg->raw without clearing the negative reg->range sentinel values.
>
> This lets is_pkt_ptr_branch_taken() choose one branch direction and
> skip going through the other. Fix this by clearing negative pkt range
> values (that is, AT_PKT_END and BEYOND_PKT_END) after arithmetic on
> pkt pointers. This ensures is_pkt_ptr_branch_taken() returns unknown
> and both branches are properly verified.
>
> [...]
Here is the summary with links:
- [bpf-next,1/2] bpf: Drop pkt_end markers on arithmetic to prevent is_pkt_ptr_branch_taken
https://git.kernel.org/bpf/bpf-next/c/9f118095dd34
- [bpf-next,2/2] selftests/bpf: Add test for stale pkt range after scalar arithmetic
https://git.kernel.org/bpf/bpf-next/c/8697bdd67be8
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] 3+ messages in thread
end of thread, other threads:[~2026-04-09 20:20 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-09 15:50 [PATCH bpf-next 1/2] bpf: Drop pkt_end markers on arithmetic to prevent is_pkt_ptr_branch_taken Daniel Borkmann
2026-04-09 15:50 ` [PATCH bpf-next 2/2] selftests/bpf: Add test for stale pkt range after scalar arithmetic Daniel Borkmann
2026-04-09 20:20 ` [PATCH bpf-next 1/2] bpf: Drop pkt_end markers on arithmetic to prevent is_pkt_ptr_branch_taken 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