nvme-tcp: control message handling for recvmsg()
authorHannes Reinecke <hare@suse.de>
Thu, 24 Aug 2023 14:39:16 +0000 (16:39 +0200)
committerKeith Busch <kbusch@kernel.org>
Wed, 11 Oct 2023 17:11:55 +0000 (10:11 -0700)
kTLS is sending TLS ALERT messages as control messages for recvmsg().
As we can't do anything sensible with it just abort the connection
and let the userspace agent to a re-negotiation.

Signed-off-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Keith Busch <kbusch@kernel.org>
drivers/nvme/host/tcp.c

index 696fc2a7da52f27cf45e1ddd2ff71736996c2d09..69975b655179c01c1b100806e816d1f2df5460c6 100644 (file)
@@ -14,6 +14,7 @@
 #include <net/sock.h>
 #include <net/tcp.h>
 #include <net/tls.h>
+#include <net/tls_prot.h>
 #include <net/handshake.h>
 #include <linux/blk-mq.h>
 #include <crypto/hash.h>
@@ -1369,6 +1370,8 @@ static int nvme_tcp_init_connection(struct nvme_tcp_queue *queue)
 {
        struct nvme_tcp_icreq_pdu *icreq;
        struct nvme_tcp_icresp_pdu *icresp;
+       char cbuf[CMSG_LEN(sizeof(char))] = {};
+       u8 ctype;
        struct msghdr msg = {};
        struct kvec iov;
        bool ctrl_hdgst, ctrl_ddgst;
@@ -1406,11 +1409,23 @@ static int nvme_tcp_init_connection(struct nvme_tcp_queue *queue)
        memset(&msg, 0, sizeof(msg));
        iov.iov_base = icresp;
        iov.iov_len = sizeof(*icresp);
+       if (queue->ctrl->ctrl.opts->tls) {
+               msg.msg_control = cbuf;
+               msg.msg_controllen = sizeof(cbuf);
+       }
        ret = kernel_recvmsg(queue->sock, &msg, &iov, 1,
                        iov.iov_len, msg.msg_flags);
        if (ret < 0)
                goto free_icresp;
-
+       if (queue->ctrl->ctrl.opts->tls) {
+               ctype = tls_get_record_type(queue->sock->sk,
+                                           (struct cmsghdr *)cbuf);
+               if (ctype != TLS_RECORD_TYPE_DATA) {
+                       pr_err("queue %d: unhandled TLS record %d\n",
+                              nvme_tcp_queue_id(queue), ctype);
+                       return -ENOTCONN;
+               }
+       }
        ret = -EINVAL;
        if (icresp->hdr.type != nvme_tcp_icresp) {
                pr_err("queue %d: bad type returned %d\n",