]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
nvme-tcp: sanitize request list handling
authorHannes Reinecke <hare@kernel.org>
Wed, 28 May 2025 06:45:33 +0000 (08:45 +0200)
committerChristoph Hellwig <hch@lst.de>
Wed, 4 Jun 2025 08:01:51 +0000 (10:01 +0200)
Validate the request in nvme_tcp_handle_r2t() to ensure it's not part of
any list, otherwise a malicious R2T PDU might inject a loop in request
list processing.

Signed-off-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Christoph Hellwig <hch@lst.de>
drivers/nvme/host/tcp.c

index ca5c03f8d4776b970c68734ee64dcaf91d6cdf9c..b37028320edd46b398f3940eb5aeb4c64b20363b 100644 (file)
@@ -452,7 +452,8 @@ nvme_tcp_fetch_request(struct nvme_tcp_queue *queue)
                        return NULL;
        }
 
-       list_del(&req->entry);
+       list_del_init(&req->entry);
+       init_llist_node(&req->lentry);
        return req;
 }
 
@@ -560,6 +561,8 @@ static int nvme_tcp_init_request(struct blk_mq_tag_set *set,
        req->queue = queue;
        nvme_req(rq)->ctrl = &ctrl->ctrl;
        nvme_req(rq)->cmd = &pdu->cmd;
+       init_llist_node(&req->lentry);
+       INIT_LIST_HEAD(&req->entry);
 
        return 0;
 }
@@ -764,6 +767,14 @@ static int nvme_tcp_handle_r2t(struct nvme_tcp_queue *queue,
                return -EPROTO;
        }
 
+       if (llist_on_list(&req->lentry) ||
+           !list_empty(&req->entry)) {
+               dev_err(queue->ctrl->ctrl.device,
+                       "req %d unexpected r2t while processing request\n",
+                       rq->tag);
+               return -EPROTO;
+       }
+
        req->pdu_len = 0;
        req->h2cdata_left = r2t_length;
        req->h2cdata_offset = r2t_offset;
@@ -2638,6 +2649,8 @@ static void nvme_tcp_submit_async_event(struct nvme_ctrl *arg)
        ctrl->async_req.offset = 0;
        ctrl->async_req.curr_bio = NULL;
        ctrl->async_req.data_len = 0;
+       init_llist_node(&ctrl->async_req.lentry);
+       INIT_LIST_HEAD(&ctrl->async_req.entry);
 
        nvme_tcp_queue_request(&ctrl->async_req, true);
 }