All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jiayuan Chen <jiayuan.chen@linux.dev>
To: bpf@vger.kernel.org
Subject: Re: [PATCH bpf 1/2] bpf, sockmap: Stop reporting EPIPE on zero-length skb redirect
Date: Mon, 26 Oct 2026 09:59:00 +0800	[thread overview]
Message-ID: <23181ba7-e4ef-4475-92ee-366e0ca2dcf0@linux.dev> (raw)
In-Reply-To: <20261025-sockmap-bare-fin-v1-1-bb8feae7c4a7@eliskeggs.com>


On 10/26/26 7:41 AM, Eli Skeggs via B4 Relay wrote:
> From: Eli Skeggs <kernel@eliskeggs.com>
>
> A FIN can arrive on a packet with no data. In that case, tcp_read_skb()
> produces an empty skb, and the attached BPF stream_verdict program may
> choose to redirect the skb to another socket. Further data redirected to
> that socket from any socket gets dropped, and the target socket starts
> reporting EPIPE. A userspace application may see that EPIPE and decide
> the socket is no longer usable. For a BPF-based proxy, this can break a
> bidirectional stream, truncating the response instead of leaving the
> socket half-open.
>
> Prior to the introduction of tcp_read_skb(), tcp_read_sock() never
> passed a zero-length skb to its actor, sk_psock_verdict_recv(). When a
> redirected skb landed in sk_psock_backlog(), it was always non-empty.
> tcp_read_skb() deviated from the historical behavior by passing any
> zero-length skbs to recv_actor(), exposing this latent bug by adding
> zero-length skbs to a queue that hadn't previously received them.  When
> sk_psock_backlog() encounters a zero-length skb, it interprets ret == 0
> as a hard error, reports EPIPE, and clears the transmit flag.
>
> Treat a return of 0 as success when there is no data to send, while
> continuing to fail on a 0 return with residual bytes. The loop exits
> without incident on an empty skb, and the skb gets cleaned up as usual.
> On an ingress redirect, the empty message is still queued as before, but
> the target socket no longer reports EPIPE.

The target can't receive anything after that though. The empty msg sits
at the head of psock->ingress_msg and nothing ever dequeues it:

__sk_msg_recvmsg()
   sge->length == 0 -> copy == 0 -> copied = -EFAULT; goto out;

The goto skips sk_psock_dequeue_msg() at the end of the loop. Then
tcp_bpf_recvmsg_parser() sees -EFAULT, is_next_msg_fin() finds the FIN
flag on the redirected skb and returns 0. Every later recv() hits the
same msg and returns 0 again, while data queued behind it is never read.
Only sk_psock_purge_ingress_msg() on psock teardown frees it.

So the user gets EOF on a socket whose peer never closed, and everything
redirected to it after the FIN is lost. Without a verdict prog on the
target it is worse, tcp_bpf_recvmsg() returns -EFAULT forever.

Since this patch is already about the zero-length skb, can you handle
the ingress side too? E.g. in sk_psock_skb_ingress(), don't queue an
empty msg when len is 0 and the skb was redirected (skb->sk != sk). The
self PASS case must keep its empty msg since is_next_msg_fin() depends
on it.


> Fixes: 965b57b469a5 ("net: Introduce a new proto_ops ->read_skb()")
> Signed-off-by: Eli Skeggs <kernel@eliskeggs.com>
> ---
>   net/core/skmsg.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/core/skmsg.c b/net/core/skmsg.c
> index df385a5a961e..f9b2e3486cfb 100644
> --- a/net/core/skmsg.c
> +++ b/net/core/skmsg.c
> @@ -716,7 +716,7 @@ static void sk_psock_backlog(struct work_struct *work)
>   			if (!sock_flag(psock->sk, SOCK_DEAD))
>   				ret = sk_psock_handle_skb(psock, skb, off,
>   							  len, ingress);
> -			if (ret <= 0) {
> +			if (ret < 0 || (!ret && len)) {
>   				if (ret == -EAGAIN) {
>   					sk_psock_skb_state(psock, state, len, off);
>   					/* Restore redir info we cleared before */
>

  parent reply	other threads:[~2026-10-26  1:59 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-25 23:41 [PATCH bpf 0/2] bpf, sockmap: Fix dropped data and EPIPE on empty skb redirect Eli Skeggs
2026-10-25 23:41 ` Eli Skeggs via B4 Relay
2026-10-25 23:41 ` [PATCH bpf 1/2] bpf, sockmap: Stop reporting EPIPE on zero-length " Eli Skeggs
2026-10-25 23:41   ` Eli Skeggs via B4 Relay
2026-10-26  1:51   ` Alexei Starovoitov
2026-10-26  2:25     ` Eli Skeggs
2026-10-26  1:59   ` Jiayuan Chen [this message]
2026-10-26  3:17     ` Eli Skeggs
2026-10-26  6:32       ` Jiayuan Chen
2026-10-25 23:41 ` [PATCH bpf 2/2] selftests/bpf: Redirect a bare FIN to another socket's egress Eli Skeggs
2026-10-25 23:41   ` Eli Skeggs via B4 Relay
2026-10-25 23:55   ` sashiko-bot
2026-10-26  0:28     ` Eli Skeggs

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=23181ba7-e4ef-4475-92ee-366e0ca2dcf0@linux.dev \
    --to=jiayuan.chen@linux.dev \
    --cc=bpf@vger.kernel.org \
    /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.