Re: [PATCH bpf 1/2] bpf, sockmap: Stop reporting EPIPE on zero-length skb redirect
From: Jiayuan Chen
Date: Mon Oct 26 2026 - 02:35:10 EST
On 10/26/26 11:17 AM, Eli Skeggs wrote:
On Mon, Oct 26, 2026 at 09:59:00AM +0800, Jiayuan Chen wrote:
On 10/26/26 7:41 AM, Eli Skeggs via B4 Relay wrote:Yep, thanks for pointing that out.
From: Eli Skeggs <kernel@xxxxxxxxxxxxx>The target can't receive anything after that though. The empty msg sits
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.
at the head of psock->ingress_msg and nothing ever dequeues 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.
Alexei suggested skipping empty skbs in sk_psock_backlog():
https://lore.kernel.org/all/DMEE6SW3UE97.2DF11HBEBKYYI@xxxxxxxxx/
To your point, I think the critical difference between these approaches
happens when the sk's backlog queue is not empty and the socket's own
FIN (the self PASS FIN) gets queued. In that case, we rely on the empty
msg to correctly update copied_seq, and skipping it means the copied
sequence number ends up 1 behind rcv_nxt.
This path is already broken: when a socket's FIN gets queued behind
other skbs, the backlog reports the erroneous EPIPE just as in the
redirect case.
I do like the simplicity of skipping the empty skbs entirely. I don't
immediately see what the consequence is for copied_seq being behind in
this terminal state, but the approach that updates copied_seq does seem
strictly more correct.
Is that the right interpretation? Let me know what direction I should
take for v2.
Yes, go with Alexei's suggestion. Skipping zero-length skbs in
sk_psock_backlog() also covers the ingress redirect case I raised,
since the empty msg is never queued. copied_seq being 1 behind
rcv_nxt is fine now, plain TCP sits in that state until the user reads
EOF, and nothing on the psock side depends on it.