Netdev List
 help / color / mirror / Atom feed
From: netdev-bot+sashiko@kernel.org
To: alexei.starovoitov@gmail.com
Cc: bpf@vger.kernel.org, netdev@vger.kernel.org,
	daniel@iogearbox.net, andrii@kernel.org, eddyz87@gmail.com,
	memxor@gmail.com, john.fastabend@gmail.com, jakub@cloudflare.com,
	jiayuan.chen@linux.dev, davem@davemloft.net, edumazet@kernel.org,
	kuba@kernel.org, pabeni@redhat.com, horms@kernel.org,
	kuniyu@google.com, willemb@google.com, matttbe@kernel.org,
	mptcp@lists.linux.dev, mason@kernel.org, josef@toxicpanda.com
Subject: Re: [PATCH bpf v2 03/15] bpf, sockmap: Don't let an SK_PASS verdict cover the next message
Date: Tue, 03 Nov 2026 21:37:57 +0000	[thread overview]
Message-ID: <179374187706.488855.8366350890804573396@kernel.org> (raw)
In-Reply-To: <20261102072112.4160195-4-alexei.starovoitov@gmail.com>

Thank you for your contribution! Sashiko AI review found 3 potential
issue(s) to consider.

Critical: 1 · High: 1 · Medium: 1 · Low: 0

If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).

- [Critical] Use-after-free of psock->cork.
- [High] The fix is incomplete when the verdict has a byte budget
  (psock->apply_bytes != 0).
- [Medium] The patch resets eval early, which lets one sender's bytes be
  charged against another sender's verdict and end that verdict early.

--

bpf, sockmap: Don't let an SK_PASS verdict cover the next message

This commit changes the __SK_PASS branch of tcp_bpf_send_verdict(). When
psock->apply_bytes is 0, it now resets psock->eval to __SK_NONE before
tcp_bpf_push(). When the push fails, it subtracts the bytes that went out
from apply_bytes and ends the verdict if apply_bytes reaches 0.

> diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c
> index d90bcc911b36b..b016aa419fb2d 100644
> --- a/net/ipv4/tcp_bpf.c
> +++ b/net/ipv4/tcp_bpf.c
> @@ -457,8 +457,22 @@ static int tcp_bpf_send_verdict(struct sock *sk, struct sk_psock *psock,
>  
>  	switch (psock->eval) {
>  	case __SK_PASS:
> +		/* The push may sleep without the socket lock, and it may fail */
> +		if (!psock->apply_bytes)
> +			psock->eval = __SK_NONE;

[Severity: High]

When psock->apply_bytes is not 0, eval stays __SK_PASS during the push.
The budget is still debited only after tcp_bpf_push() returns. Can a
second sender on the same socket still get past the prog here?

This call chain releases the socket lock:

tcp_bpf_push()->tcp_sendmsg_locked()->sk_stream_wait_memory()->sk_wait_event()

While sender A sleeps there, sender B can enter tcp_bpf_send_verdict(). B
sees eval == __SK_PASS, so the prog doesn't run, and B computes its tosend
from the budget before A's bytes are taken out:

	tosend = msg->sg.size;
	if (psock->apply_bytes && psock->apply_bytes < tosend)
		tosend = psock->apply_bytes;

A's bytes are subtracted only later, by sk_msg_apply_bytes(psock, tosend)
on success or by the new sk_msg_apply_bytes(psock, origsize -
msg->sg.size) on failure.

If both pushes succeed, a verdict that bpf_msg_apply_bytes() limited to N
bytes covers up to 2N bytes. If A's message alone uses up the budget, B's
message is the next message, and it passes without running the prog.

The commit message says:

    When apply_bytes is not 0, eval stays __SK_PASS during the push, and
    the prog does not run for another message, as today. The verdict must
    still cover the bytes that a failed push does not send. But such a
    message also lowers apply_bytes.

But B's message is sized against the budget before A's in-flight bytes
are removed from it. Would it be better to reserve the budget before the
push? That means debiting tosend, and ending the verdict when the budget
reaches 0, before calling tcp_bpf_push(), instead of subtracting after a
failure.

The __SK_PASS branch also looks unchanged at the end of the series.

> +		origsize = msg->sg.size;
>  		ret = tcp_bpf_push(sk, msg, tosend, flags, true);

[Severity: Critical]

Can another sender free msg while this push sleeps?

msg can be psock->cork here. tcp_bpf_sendmsg() picks it up with:

		if (psock->cork) {
			msg_tx = psock->cork;

The __SK_REDIRECT branch detaches psock->cork before release_sock(). The
__SK_PASS branch leaves it attached during tcp_bpf_push(). tcp_bpf_push()
keeps sge and page pointing into the cork's sg ring across
tcp_sendmsg_locked(), and that call can sleep in sk_stream_wait_memory()
without the socket lock.

With this patch and apply_bytes == 0 (the default), eval is __SK_NONE
during that sleep. Sender B can take the lock, reuse the same psock->cork,
append to it, and run the prog on A's partly sent cork. If the prog
returns SK_REDIRECT, B's __SK_REDIRECT branch does:

		if (psock->cork) {
			cork = true;
			psock->cork = NULL;
		}
		...
		if (cork) {
			sk_msg_free(sk, msg);
			kfree(msg);

When A resumes, tcp_bpf_push() writes into the freed struct sk_msg:

		msg->sg.size -= ret;
		sge->offset += ret;
		sge->length -= ret;

It may also retry with, or call put_page() on, a page that was already
released. If the push failed, the new failure path reads msg->sg.size and
calls sk_msg_free(sk, msg) on the freed object.

If B's prog returns SK_DROP instead, sk_msg_free() in the __SK_DROP branch
drops page references that A is still using.

The shared-cork problem with two PASS senders already existed. The kfree()
variant used to need a third sender to end a byte-limited verdict. The
early reset makes it reachable with only two senders.

The later commit "bpf, sockmap: Check that the redirected message is the
cork" also says that "a cork is still not safe for two senders on one
socket". The __SK_PASS branch is unchanged at the end of the series.

Is it safe to reset eval here while psock->cork is still attached and
being pushed?

>  		if (unlikely(ret)) {
> +			/* A part of it may have gone out */
> +			sk_msg_apply_bytes(psock, origsize - msg->sg.size);
> +			/* Another sender can use up the rest during the push */
> +			if (!psock->apply_bytes) {
> +				psock->eval = __SK_NONE;
> +				if (psock->sk_redir) {
> +					sock_put(psock->sk_redir);
> +					psock->sk_redir = NULL;
> +				}
> +			}

[Severity: Medium]

With the early reset, can sender A's bytes be charged against a verdict
that another sender installed?

When apply_bytes is 0 on entry, A's tosend is its whole message. eval is
now __SK_NONE while A sleeps in tcp_sendmsg_locked(). Sender B can take
the socket lock and run the prog, which installs B's verdict:

net/core/skmsg.c:sk_psock_msg_verdict() {
    ...
	psock->apply_bytes = msg->apply_bytes;
	if (ret == __SK_REDIRECT) {
    ...
		psock->sk_redir = msg->sk_redir;
		sock_hold(psock->sk_redir);
    ...
}

If B's apply_bytes is larger than B's message, B's verdict (PASS, DROP or
REDIRECT) stays active with some budget left. When A resumes, it
subtracts its bytes from B's budget, even though A's own verdict had no
byte limit. On success that happens through the unchanged
sk_msg_apply_bytes(psock, tosend). On failure it happens through the new
call above.

If that brings apply_bytes to 0, either this new block or the common block
at the end of tcp_bpf_send_verdict() sets eval to __SK_NONE and drops
psock->sk_redir:

	if (likely(!ret)) {
		if (!psock->apply_bytes) {
			psock->eval =  __SK_NONE;
			if (psock->sk_redir) {
				sock_put(psock->sk_redir);
				psock->sk_redir = NULL;
			}
		}

That ends B's verdict before it has covered the bytes B's prog asked for.
Later bytes that should have been dropped or redirected get a fresh prog
run instead.

Before this patch, eval stayed __SK_PASS during A's push, so this needed a
third sender. Could A record locally whether its verdict had a byte limit
on entry? Then it would touch psock->apply_bytes, eval and sk_redir only
when that is true and the verdict is still its own.

>  			*copied -= sk_msg_free(sk, msg);
>  			break;
>  		}

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261102072112.4160195-1-alexei.starovoitov%40gmail.com

  parent reply	other threads:[~2026-11-03 21:37 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-02  7:20 [PATCH bpf v2 00/15] bpf, sockmap: Fixes for verdicts, redirects, corks and recvmsg() Alexei Starovoitov
2026-11-02  7:20 ` [PATCH bpf v2 01/15] bpf, sockmap: Write sg.start when recvmsg() faults Alexei Starovoitov
2026-11-02  8:32   ` Jiayuan Chen
2026-11-02  7:20 ` [PATCH bpf v2 02/15] bpf, sockmap: Don't let an SK_DROP verdict stick Alexei Starovoitov
2026-11-02  8:45   ` Jiayuan Chen
2026-11-02 18:47   ` John Fastabend
2026-11-02  7:21 ` [PATCH bpf v2 03/15] bpf, sockmap: Don't let an SK_PASS verdict cover the next message Alexei Starovoitov
2026-11-02 18:51   ` John Fastabend
2026-11-02 22:44     ` Alexei Starovoitov
2026-11-03 21:37   ` netdev-bot+sashiko [this message]
2026-11-04  0:28     ` Alexei Starovoitov
2026-11-02  7:21 ` [PATCH bpf v2 04/15] bpf, sockmap: Subtract all dropped bytes from the return value Alexei Starovoitov
2026-11-02 11:19   ` Jiayuan Chen
2026-11-02 19:12   ` John Fastabend
2026-11-02  7:21 ` [PATCH bpf v2 05/15] bpf, sockmap: Clear the resume state of a stopped psock Alexei Starovoitov
2026-11-02 11:40   ` Jiayuan Chen
2026-11-02 19:16     ` John Fastabend
2026-11-02  7:21 ` [PATCH bpf v2 06/15] bpf, sockmap: Give no progs to a TCP listener Alexei Starovoitov
2026-11-02 12:00   ` Jiayuan Chen
2026-11-02 19:31   ` John Fastabend
2026-11-03 21:37   ` netdev-bot+sashiko
2026-11-04  0:29     ` Alexei Starovoitov
2026-11-02  7:21 ` [PATCH bpf v2 07/15] bpf, sockmap: Check the target of an egress redirect before each send Alexei Starovoitov
2026-11-02 12:32   ` Jiayuan Chen
2026-11-02 16:18     ` Alexei Starovoitov
2026-11-02 19:36   ` John Fastabend
2026-11-03 21:38   ` netdev-bot+sashiko
2026-11-04  0:29     ` Alexei Starovoitov
2026-11-02  7:21 ` [PATCH bpf v2 08/15] net: Leave sk_stream_wait_memory() once the socket is dead Alexei Starovoitov
2026-11-02 12:54   ` Jiayuan Chen
2026-11-02  7:21 ` [PATCH bpf v2 09/15] bpf, sockmap: Check the TCP state in recvmsg() Alexei Starovoitov
2026-11-02 15:15   ` Jiayuan Chen
2026-11-02 16:57   ` Matthieu Baerts
2026-11-03 21:38   ` netdev-bot+sashiko
2026-11-04  0:29     ` Alexei Starovoitov
2026-11-02  7:21 ` [PATCH bpf v2 10/15] bpf, sockmap: Reset the copy position when corking Alexei Starovoitov
2026-11-03  1:39   ` Jiayuan Chen
2026-11-02  7:21 ` [PATCH bpf v2 11/15] bpf, sockmap: Don't copy 0 bytes into a full cork Alexei Starovoitov
2026-11-03  1:41   ` Jiayuan Chen
2026-11-02  7:21 ` [PATCH bpf v2 12/15] bpf, sockmap: Clear the redirect target before the sk_msg prog runs Alexei Starovoitov
2026-11-03  1:58   ` Jiayuan Chen
2026-11-02  7:21 ` [PATCH bpf v2 13/15] bpf, sockmap: Check that the redirected message is the cork Alexei Starovoitov
2026-11-03  2:07   ` Jiayuan Chen
2026-11-02  7:21 ` [PATCH bpf v2 14/15] bpf, sockmap: Keep the rest of the cork after a redirect Alexei Starovoitov
2026-11-03  2:25   ` Jiayuan Chen
2026-11-03 21:38   ` netdev-bot+sashiko
2026-11-04  0:30     ` Alexei Starovoitov
2026-11-02  7:21 ` [PATCH bpf v2 15/15] bpf, sockmap: Clear the end mark of elements added by push and pop Alexei Starovoitov
2026-11-03  2:51   ` Jiayuan Chen
2026-11-02 20:11 ` [PATCH bpf v2 00/15] bpf, sockmap: Fixes for verdicts, redirects, corks and recvmsg() John Fastabend

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=179374187706.488855.8366350890804573396@kernel.org \
    --to=netdev-bot+sashiko@kernel.org \
    --cc=alexei.starovoitov@gmail.com \
    --cc=andrii@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=davem@davemloft.net \
    --cc=eddyz87@gmail.com \
    --cc=edumazet@kernel.org \
    --cc=horms@kernel.org \
    --cc=jakub@cloudflare.com \
    --cc=jiayuan.chen@linux.dev \
    --cc=john.fastabend@gmail.com \
    --cc=josef@toxicpanda.com \
    --cc=kuba@kernel.org \
    --cc=kuniyu@google.com \
    --cc=mason@kernel.org \
    --cc=matttbe@kernel.org \
    --cc=memxor@gmail.com \
    --cc=mptcp@lists.linux.dev \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=willemb@google.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox