Commit b716e688 authored by Sagi Grimberg's avatar Sagi Grimberg Committed by Keith Busch
Browse files

nvmet: fix dsm failure when payload does not match sgl descriptor



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: default avatarDakshaja Uppalapati <dakshaja@chelsio.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de&gt;,>
Reviewed-by: default avatarMax Gurtovoy <maxg@mellanox.com>
Signed-off-by: default avatarSagi Grimberg <sagi@grimberg.me>
Signed-off-by: default avatarKeith Busch <kbusch@kernel.org>
parent 4ac76436
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -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;
+1 −1
Original line number Diff line number Diff line
@@ -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)) {
+1 −1
Original line number Diff line number Diff line
@@ -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);
+1 −0
Original line number Diff line number Diff line
@@ -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);