BPF List
 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: 10+ 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 via B4 Relay
2026-10-25 23:41 ` [PATCH bpf 1/2] bpf, sockmap: Stop reporting EPIPE on zero-length " 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 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox