Skip to content

Commit

Permalink
nvmet: fix dsm failure when payload does not match sgl descriptor
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Sagi Grimberg authored and Keith Busch committed Feb 3, 2020
1 parent 4ac7643 commit b716e68
Show file tree
Hide file tree
Showing 4 changed files with 14 additions and 2 deletions.
11 changes: 11 additions & 0 deletions drivers/nvme/target/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion drivers/nvme/target/io-cmd-bdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
2 changes: 1 addition & 1 deletion drivers/nvme/target/io-cmd-file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions drivers/nvme/target/nvmet.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit b716e68

Please sign in to comment.