From: Vincent Whitchurch <vincent.whitchurch@xxxxxxxxxxxxx> If a socket is added to a sockmap with a verdict program which returns SK_PASS, splice(2) is not able to read from the socket. The verdict code removes skbs from the receive queue, checks them using the bpf program, and then re-queues them onto a separate queue (psock->ingress_msg). The sockmap code modifies the TCP recvmsg hook to check this second queue also so that works. But the splice_read hooks is not modified and the default tcp_read_splice() only reads the normal receive queue so it never sees the skbs which have been re-queued. Fix it by using copy_splice_read() when replacing the proto for the sockmap. This could eventually be replaced with a more efficient custom version. Signed-off-by: Vincent Whitchurch <vincent.whitchurch@xxxxxxxxxxxxx> --- net/ipv4/tcp_bpf.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c index 53b0d62fd2c2..b7c110dedd35 100644 --- a/net/ipv4/tcp_bpf.c +++ b/net/ipv4/tcp_bpf.c @@ -3,6 +3,7 @@ #include <linux/skmsg.h> #include <linux/filter.h> +#include <linux/fs.h> #include <linux/bpf.h> #include <linux/init.h> #include <linux/wait.h> @@ -378,6 +379,13 @@ static int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, return ret; } +static ssize_t tcp_bpf_splice_read(struct socket *sock, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags) +{ + return copy_splice_read(sock->file, ppos, pipe, len, flags); +} + static int tcp_bpf_send_verdict(struct sock *sk, struct sk_psock *psock, struct sk_msg *msg, int *copied, int flags) { @@ -605,6 +613,7 @@ static void tcp_bpf_rebuild_protos(struct proto prot[TCP_BPF_NUM_CFGS], prot[TCP_BPF_BASE].destroy = sock_map_destroy; prot[TCP_BPF_BASE].close = sock_map_close; prot[TCP_BPF_BASE].recvmsg = tcp_bpf_recvmsg; + prot[TCP_BPF_BASE].splice_read = tcp_bpf_splice_read; prot[TCP_BPF_BASE].sock_is_readable = sk_msg_is_readable; prot[TCP_BPF_TX] = prot[TCP_BPF_BASE]; -- 2.34.1