nvme-tcp: fix possible req->offset corruption
authorVarun Prakash <varun@chelsio.com>
Tue, 26 Oct 2021 13:31:55 +0000 (19:01 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 2 Nov 2021 18:48:22 +0000 (19:48 +0100)
commit ce7723e9cdae4eb3030da082876580f4b2dc0861 upstream.

With commit db5ad6b7f8cd ("nvme-tcp: try to send request in queue_rq
context") r2t and response PDU can get processed while send function
is executing.

Current data digest send code uses req->offset after kernel_sendmsg(),
this creates a race condition where req->offset gets reset before it
is used in send function.

This can happen in two cases -
1. Target sends r2t PDU which resets req->offset.
2. Target send response PDU which completes the req and then req is
   used for a new command, nvme_tcp_setup_cmd_pdu() resets req->offset.

Fix this by storing req->offset in a local variable and using
this local variable after kernel_sendmsg().

Fixes: db5ad6b7f8cd ("nvme-tcp: try to send request in queue_rq context")
Signed-off-by: Varun Prakash <varun@chelsio.com>
Reviewed-by: Keith Busch <kbusch@kernel.org>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/nvme/host/tcp.c

index afef377..e99d439 100644 (file)
@@ -1037,6 +1037,7 @@ static int nvme_tcp_try_send_data_pdu(struct nvme_tcp_request *req)
 static int nvme_tcp_try_send_ddgst(struct nvme_tcp_request *req)
 {
        struct nvme_tcp_queue *queue = req->queue;
+       size_t offset = req->offset;
        int ret;
        struct msghdr msg = { .msg_flags = MSG_DONTWAIT };
        struct kvec iov = {
@@ -1053,7 +1054,7 @@ static int nvme_tcp_try_send_ddgst(struct nvme_tcp_request *req)
        if (unlikely(ret <= 0))
                return ret;
 
-       if (req->offset + ret == NVME_TCP_DIGEST_LENGTH) {
+       if (offset + ret == NVME_TCP_DIGEST_LENGTH) {
                nvme_tcp_done_send_req(queue);
                return 1;
        }