On Sun, Oct 25, 2026 at 04:41 PM Eli Skeggs via B4 Relay [off-list ref] wrote:
On an ingress redirect, the empty message is still queued as before, but
the target socket no longer reports EPIPE.
That leaves the target broken.
Nothing dequeues the empty sk_msg. __sk_msg_recvmsg() sees
sge->length == 0, returns -EFAULT and leaves it at the head of ingress_msg.
tcp_bpf_recvmsg_parser() finds FIN in is_next_msg_fin(), returns 0 and
does copied_seq++ on a socket that didn't receive any FIN.
So every recv() on the target returns 0 and moves its copied_seq further
past rcv_nxt, and the data redirected from other sockets stays behind
that msg forever.
[...]
- if (ret <= 0) {
+ if (ret < 0 || (!ret && len)) {
Lets skip empty skbs instead. That covers both directions.
The socket's own FIN that goes through the backlog is not queued either,
but SOCK_DONE check in tcp_bpf_recvmsg_parser() returns 0 anyway.
Something like this (compile tested only):
diff --git a/net/core/skmsg.c b/net/core/skmsg.c
index df385a5..a5003c7 100644
--- a/net/core/skmsg.c
+++ b/net/core/skmsg.c
@@ -711,7 +711,7 @@ static void sk_psock_backlog(struct work_struct *work)
ingress = skb_bpf_ingress(skb);
skb_bpf_redirect_clear(skb);
- do {
+ while (len) {
ret = -EIO;
if (!sock_flag(psock->sk, SOCK_DEAD))
ret = sk_psock_handle_skb(psock, skb, off,@@ -735,7 +735,7 @@ static void sk_psock_backlog(struct work_struct *work)
}
off += ret;
len -= ret;
- } while (len);
+ }
/* The entire skb sent, clear state */
sk_psock_skb_state(psock, state, 0, 0);
pw-bot: cr