BPF List
 help / color / mirror / Atom feed
* [PATCH] bpf, sockmap: Fix ring capacity invariant break in bpf_msg_push_data()
@ 2026-11-12  3:13 bo cao
  2026-11-12  3:42 ` sashiko-bot
  2026-11-12  4:20 ` Alexei Starovoitov
  0 siblings, 2 replies; 3+ messages in thread
From: bo cao @ 2026-11-12  3:13 UTC (permalink / raw)
  To: bpf; +Cc: ast, daniel, john.fastabend, gregkh, Bo Cao

From: Bo Cao <treebacker@foxmail.com>

A push at msg->size ends the element walk on the ring's free slot, so
the "no space, absorb by copy" fallback reads the free slot's length
instead of the last live element's. Nothing is absorbed and the split
path runs anyway: with the ring already holding MAX_MSG_FRAGS live
elements it advances sg.end onto sg.start, all NR_MSG_FRAG_IDS slots
become live, and the occupancy (the distance from sg.start to
sg.end) reads 0 -- "empty". Every capacity check in push/pop is then
bypassed and later transforms corrupt the element list.

Without the fix, a single send() with an SK_MSG verdict program on a
full ring deterministically crashes the SK_DROP teardown (arm64,
7.4.0-rc2 + the bpf master sockmap series):

  Unable to handle kernel NULL pointer dereference at virtual address 0000000000000008
  ESR = 0x0000000096000004  FSC = 0x04: level 0 translation fault
  Internal error: Oops: 0000000096000004 [#1]  SMP
  CPU: 2 UID: 0 PID: 546 Comm: skmsg_panic Tainted: G        W           7.4.0-rc2 #1 PREEMPT(full)
  pc : sk_msg_free_elem+0x90/0x148
  lr : __sk_msg_free+0x8c/0x10c
  x14: 4141414141414141
  Call trace:
   sk_msg_free_elem+0x90/0x148
   __sk_msg_free+0x8c/0x10c
   sk_msg_free+0x18/0x24
   tcp_bpf_sendmsg+0x298/0xa54
   inet_sendmsg+0x44/0x70
   __sys_sendto+0x120/0x198

put_page() on a zeroed scatterlist entry. With the fix the helper
returns -ENOSPC, the message frees normally, and the crash is gone.

Never read the free slot in the fallback: absorb into the last live
element when the walk ended on it and the ring is full, or fail with
-ENOSPC if there is nothing to absorb, so the guard slot is never
consumed.

The bug was found with LLM-assisted source auditing and verified end
to end: it is reachable with CAP_BPF/CAP_NET_ADMIN and confirmed
exploitable for local privilege escalation (details reported to the
maintainers separately). Regression tested with
tools/testing/selftests/bpf/test_sockmap.

Tested on top of v7.4-rc2 plus the sockmap fix series currently in
bpf/bpf.git master (b889ea1f6dbe..0048086bd361); neither that series
nor the June sk_msg fixes (f3f34ca45b96 and friends) touch the ring
capacity invariant, and the patch applies to mainline and bpf master
alike.

Fixes: 6fff607e2f14 ("bpf: sk_msg program helper bpf_msg_push_data")
Signed-off-by: Bo Cao <treebacker@foxmail.com>
---
 net/core/filter.c | 25 +++++++++++++++++++++++--
 1 file changed, 23 insertions(+), 2 deletions(-)

diff --git a/net/core/filter.c b/net/core/filter.c
index 1f81a3dd6a5c..371c090d7f8d 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -2892,8 +2892,29 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_msg *, msg, u32, start,
 	 * offset case because its the common case for inserting a
 	 * header.
 	 */
-	if (!space || (space == 1 && start != offset))
-		copy = msg->sg.data[i].length;
+	if (!space || (space == 1 && start != offset)) {
+		/* A push at msg->size leaves the walk on the ring's free
+		 * slot, which is not a live element: its length reads 0
+		 * (or stale data left by an earlier ring rotation), so
+		 * the copy fallback would absorb nothing and the split
+		 * path below would run. With the ring already full
+		 * (space == 0) that path advances sg.end onto sg.start,
+		 * leaving all NR_MSG_FRAG_IDS slots live -- the ring can
+		 * no longer tell "full" from "empty" and later
+		 * transforms corrupt state. Absorb into the last live
+		 * element instead, or fail if there is nothing to absorb.
+		 */
+		if (i == msg->sg.end) {
+			if (!space) {
+				sk_msg_iter_var_prev(i);
+				copy = msg->sg.data[i].length;
+				if (!copy)
+					return -ENOSPC;
+			}
+		} else {
+			copy = msg->sg.data[i].length;
+		}
+	}
 
 	if (unlikely(copy + len < copy))
 		return -EINVAL;
-- 
2.39.5 (Apple Git-154)


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

end of thread, other threads:[~2026-11-12  4:20 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-12  3:13 [PATCH] bpf, sockmap: Fix ring capacity invariant break in bpf_msg_push_data() bo cao
2026-11-12  3:42 ` sashiko-bot
2026-11-12  4:20 ` Alexei Starovoitov

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