]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
nvmet: fix dsm failure when payload does not match sgl descriptor
authorSagi Grimberg <sagi@grimberg.me>
Mon, 27 Jan 2020 07:23:28 +0000 (23:23 -0800)
committerKeith Busch <kbusch@kernel.org>
Mon, 3 Feb 2020 18:00:24 +0000 (03:00 +0900)
The host is allowed to pass the controller an sgl describing a buffer
that is larger than the dsm payload itself, allow it when executing
dsm.

Reported-by: Dakshaja Uppalapati <dakshaja@chelsio.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>,
Reviewed-by: Max Gurtovoy <maxg@mellanox.com>
Signed-off-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Keith Busch <kbusch@kernel.org>
drivers/nvme/target/core.c
drivers/nvme/target/io-cmd-bdev.c
drivers/nvme/target/io-cmd-file.c
drivers/nvme/target/nvmet.h

index 35810a0a8d2122dad7eb1e3dc6398b6c096ed8b2..461987f669c50dffd10b9359c7b7153de23ed6a5 100644 (file)
@@ -939,6 +939,17 @@ bool nvmet_check_data_len(struct nvmet_req *req, size_t data_len)
 }
 EXPORT_SYMBOL_GPL(nvmet_check_data_len);
 
+bool nvmet_check_data_len_lte(struct nvmet_req *req, size_t data_len)
+{
+       if (unlikely(data_len > req->transfer_len)) {
+               req->error_loc = offsetof(struct nvme_common_command, dptr);
+               nvmet_req_complete(req, NVME_SC_SGL_INVALID_DATA | NVME_SC_DNR);
+               return false;
+       }
+
+       return true;
+}
+
 int nvmet_req_alloc_sgl(struct nvmet_req *req)
 {
        struct pci_dev *p2p_dev = NULL;
index b6fca0e421ef1bc3c0cd96394a8649803c03eb81..ea0e596be15dc5a9c72380cf39dcc8678b88bfe6 100644 (file)
@@ -280,7 +280,7 @@ static void nvmet_bdev_execute_discard(struct nvmet_req *req)
 
 static void nvmet_bdev_execute_dsm(struct nvmet_req *req)
 {
-       if (!nvmet_check_data_len(req, nvmet_dsm_len(req)))
+       if (!nvmet_check_data_len_lte(req, nvmet_dsm_len(req)))
                return;
 
        switch (le32_to_cpu(req->cmd->dsm.attributes)) {
index caebfce066056bac1c7e0adb581392f1ed9eb545..cd5670b83118f40786fac018fc3ad21c46c89a23 100644 (file)
@@ -336,7 +336,7 @@ static void nvmet_file_dsm_work(struct work_struct *w)
 
 static void nvmet_file_execute_dsm(struct nvmet_req *req)
 {
-       if (!nvmet_check_data_len(req, nvmet_dsm_len(req)))
+       if (!nvmet_check_data_len_lte(req, nvmet_dsm_len(req)))
                return;
        INIT_WORK(&req->f.work, nvmet_file_dsm_work);
        schedule_work(&req->f.work);
index 46df45e837c95bd7b3149ef4d0061d28ac16738d..eda28b22a2c87e3d8254cb8546cf512cf334e8e1 100644 (file)
@@ -374,6 +374,7 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq,
                struct nvmet_sq *sq, const struct nvmet_fabrics_ops *ops);
 void nvmet_req_uninit(struct nvmet_req *req);
 bool nvmet_check_data_len(struct nvmet_req *req, size_t data_len);
+bool nvmet_check_data_len_lte(struct nvmet_req *req, size_t data_len);
 void nvmet_req_complete(struct nvmet_req *req, u16 status);
 int nvmet_req_alloc_sgl(struct nvmet_req *req);
 void nvmet_req_free_sgl(struct nvmet_req *req);