[PATCH 5/5] SUNRPC: Bypass sock_recvmsg() for the TLS control-record receive

Chuck Lever <[email protected]>
Newsgroups org.kernel.vger.linux-nfs,org.kernel.vger.netdev
Message-ID <[email protected]>
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 <[email protected]>
---
 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.