From eb78b90ca86ada4ae022ca3335969c7e7f0b9dad Mon Sep 17 00:00:00 2001 From: Alexey Marchuk Date: Wed, 9 Sep 2020 16:19:39 +0300 Subject: [PATCH] nvme/rdma: Check that SGL descriptors fit into ICD The issue happens when SPDK RDMA initiator is connected to a remote target and this target reports rather small (or zero) ICD and we try to send several SGL descriptors. Since SGL descriptors are located in ICD, we should check that their total length fits into ICD. In other case sending such a command will cause RDMA errors (local length error) Change-Id: I8c0e8375dae799bc442ed2fab249cad2c4ccce51 Signed-off-by: Alexey Marchuk Reported-by: Or Gerlitz Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4131 Reviewed-by: Shuhei Matsumoto Reviewed-by: Ben Walker Tested-by: SPDK CI Jenkins --- lib/nvme/nvme_rdma.c | 12 +++++++++--- test/unit/lib/nvme/nvme_rdma.c/nvme_rdma_ut.c | 12 ++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/lib/nvme/nvme_rdma.c b/lib/nvme/nvme_rdma.c index d1264caf7..af1e5232d 100644 --- a/lib/nvme/nvme_rdma.c +++ b/lib/nvme/nvme_rdma.c @@ -1634,12 +1634,18 @@ nvme_rdma_build_sgl_request(struct nvme_rdma_qpair *rqpair, * Otherwise, The SGL descriptor embedded in the command must point to the list of * SGL descriptors used to describe the operation. In that case it is a last segment descriptor. */ - rdma_req->send_sgl[0].length = sizeof(struct spdk_nvme_cmd) + sizeof(struct - spdk_nvme_sgl_descriptor) * num_sgl_desc; + uint32_t descriptors_size = sizeof(struct spdk_nvme_sgl_descriptor) * num_sgl_desc; + + if (spdk_unlikely(descriptors_size > rqpair->qpair.ctrlr->ioccsz_bytes)) { + SPDK_ERRLOG("Size of SGL descriptors (%u) exceeds ICD (%u)\n", + descriptors_size, rqpair->qpair.ctrlr->ioccsz_bytes); + return -1; + } + rdma_req->send_sgl[0].length = sizeof(struct spdk_nvme_cmd) + descriptors_size; req->cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_LAST_SEGMENT; req->cmd.dptr.sgl1.unkeyed.subtype = SPDK_NVME_SGL_SUBTYPE_OFFSET; - req->cmd.dptr.sgl1.unkeyed.length = num_sgl_desc * sizeof(struct spdk_nvme_sgl_descriptor); + req->cmd.dptr.sgl1.unkeyed.length = descriptors_size; req->cmd.dptr.sgl1.address = (uint64_t)0; } diff --git a/test/unit/lib/nvme/nvme_rdma.c/nvme_rdma_ut.c b/test/unit/lib/nvme/nvme_rdma.c/nvme_rdma_ut.c index 8342e84d3..18e63a189 100644 --- a/test/unit/lib/nvme/nvme_rdma.c/nvme_rdma_ut.c +++ b/test/unit/lib/nvme/nvme_rdma.c/nvme_rdma_ut.c @@ -126,6 +126,7 @@ test_nvme_rdma_build_sgl_request(void) ctrlr.max_sges = NVME_RDMA_MAX_SGL_DESCRIPTORS; ctrlr.cdata.nvmf_specific.msdbd = 16; + ctrlr.ioccsz_bytes = 4096; rqpair.mr_map = &rmap; rqpair.qpair.ctrlr = &ctrlr; @@ -208,6 +209,17 @@ test_nvme_rdma_build_sgl_request(void) bio.iovs[1].iov_len = 1 << 24; rc = nvme_rdma_build_sgl_request(&rqpair, &rdma_req); SPDK_CU_ASSERT_FATAL(rc != 0); + + /* Test case 6: 4 SGL descriptors, size of SGL descriptors exceeds ICD. Expected: FAIL */ + ctrlr.ioccsz_bytes = 60; + bio.iovpos = 0; + req.payload_offset = 0; + req.payload_size = 0x4000; + for (i = 0; i < 4; i++) { + bio.iovs[i].iov_len = 0x1000; + } + rc = nvme_rdma_build_sgl_request(&rqpair, &rdma_req); + SPDK_CU_ASSERT_FATAL(rc == -1); } static void