SUNRPC: Capture CMSG metadata on client-side receive
authorChuck Lever <chuck.lever@oracle.com>
Wed, 7 Jun 2023 13:58:49 +0000 (09:58 -0400)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Mon, 19 Jun 2023 16:26:54 +0000 (12:26 -0400)
kTLS sockets use CMSG to report decryption errors and the need
for session re-keying.

For RPC-with-TLS, an "application data" message contains a ULP
payload, and that is passed along to the RPC client. An "alert"
message triggers connection reset. Everything else is discarded.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
net/sunrpc/xprtsock.c

index 0b2739d..7e2f962 100644 (file)
@@ -47,6 +47,8 @@
 #include <net/checksum.h>
 #include <net/udp.h>
 #include <net/tcp.h>
+#include <net/tls.h>
+
 #include <linux/bvec.h>
 #include <linux/highmem.h>
 #include <linux/uio.h>
@@ -347,13 +349,56 @@ xs_alloc_sparse_pages(struct xdr_buf *buf, size_t want, gfp_t gfp)
        return want;
 }
 
+static int
+xs_sock_process_cmsg(struct socket *sock, struct msghdr *msg,
+                    struct cmsghdr *cmsg, int ret)
+{
+       if (cmsg->cmsg_level == SOL_TLS &&
+           cmsg->cmsg_type == TLS_GET_RECORD_TYPE) {
+               u8 content_type = *((u8 *)CMSG_DATA(cmsg));
+
+               switch (content_type) {
+               case TLS_RECORD_TYPE_DATA:
+                       /* TLS sets EOR at the end of each application data
+                        * record, even though there might be more frames
+                        * waiting to be decrypted.
+                        */
+                       msg->msg_flags &= ~MSG_EOR;
+                       break;
+               case TLS_RECORD_TYPE_ALERT:
+                       ret = -ENOTCONN;
+                       break;
+               default:
+                       ret = -EAGAIN;
+               }
+       }
+       return ret;
+}
+
+static int
+xs_sock_recv_cmsg(struct socket *sock, struct msghdr *msg, int flags)
+{
+       union {
+               struct cmsghdr  cmsg;
+               u8              buf[CMSG_SPACE(sizeof(u8))];
+       } u;
+       int ret;
+
+       msg->msg_control = &u;
+       msg->msg_controllen = sizeof(u);
+       ret = sock_recvmsg(sock, msg, flags);
+       if (msg->msg_controllen != sizeof(u))
+               ret = xs_sock_process_cmsg(sock, msg, &u.cmsg, ret);
+       return ret;
+}
+
 static ssize_t
 xs_sock_recvmsg(struct socket *sock, struct msghdr *msg, int flags, size_t seek)
 {
        ssize_t ret;
        if (seek != 0)
                iov_iter_advance(&msg->msg_iter, seek);
-       ret = sock_recvmsg(sock, msg, flags);
+       ret = xs_sock_recv_cmsg(sock, msg, flags);
        return ret > 0 ? ret + seek : ret;
 }
 
@@ -379,7 +424,7 @@ xs_read_discard(struct socket *sock, struct msghdr *msg, int flags,
                size_t count)
 {
        iov_iter_discard(&msg->msg_iter, ITER_DEST, count);
-       return sock_recvmsg(sock, msg, flags);
+       return xs_sock_recv_cmsg(sock, msg, flags);
 }
 
 #if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE