svc_tcp_recvfrom() parses the RPC record stream with ->read_sock, which calls neither security_socket_recvmsg() nor the sock:sock_recv_length tracepoint. svc_tcp_recv_cmsg() still goes through sock_recvmsg(), so an LSM mediates only the TLS control records on a server socket, and sock:sock_recv_length reports only those. Partial coverage is worse than none. It makes the RPC stream look mediated and observed when it is not. Until the record stream moved to ->read_sock, an LSM saw every octet NFSD read from a TCP socket. An SELinux policy that denies SOCKET__READ to NFSD blocked the receive. After this change no call on the server's TCP receive path consults an LSM, so that denial has no effect. Dispatch ->recvmsg directly so the whole receive path behaves one way. sock_recvmsg_nosec() reaches ->recvmsg through INDIRECT_CALL_INET(), so on a retpoline build the direct dispatch costs one indirect call per control record. Control records are rare on an established connection. Signed-off-by: Chuck Lever --- net/sunrpc/svcsock.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index fe307d8314c4..ef7ac080fcd3 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -229,10 +229,16 @@ static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining) return len; } +/* + * The ->read_sock data path invokes neither security_socket_recvmsg() + * nor the sock:sock_recv_length tracepoint. Dispatch ->recvmsg + * directly so the whole receive path behaves one way. + */ static int svc_tcp_recv_cmsg(struct socket *sock, int flags, struct kvec *payload, u8 *type, unsigned int *msg_flags) { + const struct proto_ops *ops = READ_ONCE(sock->ops); union { struct cmsghdr cmsg; u8 buf[CMSG_SPACE(sizeof(u8))]; @@ -244,7 +250,7 @@ static int svc_tcp_recv_cmsg(struct socket *sock, int flags, int ret; iov_iter_kvec(&msg.msg_iter, ITER_DEST, payload, 1, payload->iov_len); - ret = sock_recvmsg(sock, &msg, flags); + ret = ops->recvmsg(sock, &msg, msg_data_left(&msg), flags); if (ret < 0) return ret; *msg_flags = msg.msg_flags; -- 2.54.0