From: sashiko-bot@kernel.org
To: "bo cao" <treebacker@foxmail.com>, bpf@vger.kernel.org
Subject: Re: [PATCH] bpf, sockmap: Fix ring capacity invariant break in bpf_msg_push_data()
Date: Thu, 12 Nov 2026 03:42:06 +0000 [thread overview]
Message-ID: <sashiko-outbox-210291@kernel.org> (raw)
In-Reply-To: <tencent_84A432FD1AE7054D384BEB36958789AAFA05@qq.com>
Thank you for your contribution! Sashiko AI review found 4 potential
issues to consider:
- [Low] bpf: non-standard multi-line comment style in
bpf_msg_push_data()
- [Low] bpf, sockmap: inaccurate -ENOSPC claim and dead check in
bpf_msg_push_data()
- [Low] bpf, sockmap: inaccurate Fixes trailer in bpf_msg_push_data()
fix
- [Low] bpf: unreachable sg.end check in bpf_msg_push_data() copy path
--
commit a346141a5e25b55660858c935ff1dea8fc5392a6
Author: Bo Cao <treebacker@foxmail.com>
> bpf, sockmap: Fix ring capacity invariant break in bpf_msg_push_data()
>
> 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>
[Severity: Low]
Prior to commit 15ab0548e310 ("bpf, sockmap: Several fixes to
bpf_msg_push_data"), bpf_msg_push_data() checked start >= offset + l after
the scatterlist walk and returned -EINVAL whenever the loop ended at
i == msg->sg.end on a non-empty ring. Commit 15ab0548e310 ("bpf, sockmap:
Several fixes to bpf_msg_push_data") relaxed that check to allow pushing at
the end of a message and added the sk_msg_iter_var_prev(i) adjustment inside
if (copy), overlooking that copy = msg->sg.data[i].length was read earlier.
Should the Fixes: tag point to that commit instead?
Fixes: 15ab0548e310 ("bpf, sockmap: Several fixes to bpf_msg_push_data")
> diff --git a/net/core/filter.c b/net/core/filter.c
> index d68b521504050..9ecb94a56d548 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.
> + */
[Severity: Low]
This isn't a bug, but BPF coding style places the opening /* of a multi-line
comment on its own line with the comment text starting on the next line.
> + 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;
[Severity: Low]
Can copy ever be zero here when !space holds, or is the commit message
inaccurate in stating that the helper returns -ENOSPC on a full ring?
Every live scatterlist element in [msg->sg.start, msg->sg.end) has a
non-zero length. When !space holds, the ring has MAX_MSG_FRAGS live
elements, so stepping i back from msg->sg.end selects the last live element
with msg->sg.data[i].length > 0; bpf_msg_push_data() then absorbs the push
into a newly allocated page and returns 0 (or -ENOMEM) rather than -ENOSPC.
[Severity: Low]
Does stepping i back from msg->sg.end here make the second msg->sg.end check
inside if (copy) unreachable dead code?
net/core/filter.c:bpf_msg_push_data() {
...
if (copy) {
int front, back;
raw = page_address(page);
if (i == msg->sg.end)
sk_msg_iter_var_prev(i);
...
}
copy is initialized to 0 and is only set to a non-zero value when
i != msg->sg.end or after the !space branch above has already decremented i
away from msg->sg.end, so i can never equal msg->sg.end when entering
if (copy).
--
Sashiko AI review · https://sashiko.dev/#/patchset/tencent_84A432FD1AE7054D384BEB36958789AAFA05@qq.com?part=1
next prev parent reply other threads:[~2026-11-12 3:42 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
2026-11-12 4:20 ` Alexei Starovoitov
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=sashiko-outbox-210291@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=treebacker@foxmail.com \
/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.