lib/nvmf: fix identify command corruption
In the previous fix:
adc2942ad
nvmf: nvmf_ctrlr_get_log_page use iovs to store the log page
a data corruption bug in the log page code was fixed. Previously, it
used req->data, which may be too short a buffer in the case that the
buffer is split across more than one IOV. req->data is never safe to use
in this situation. The code was changed to use the provided iovs instead
of req->data.
However, the identify command handling was still vulnerable to this
problem, and has been seen in real life at least with a CentOS guest VM.
The fix is basically the same: use the IOV utility functions to write
out the response instead of directly trying to use req->data.
Signed-off-by: John Levon <john.levon@nutanix.com>
Change-Id: I00445895af20e43be73189629576eee0667f86dd
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16121
Reviewed-by: Thanos Makatos <thanos.makatos@nutanix.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
parent
56fe6fdf85
commit
acc4d1766c
@ -2877,8 +2877,10 @@ nvmf_ctrlr_identify_ns_id_descriptor_list(
|
||||
ADD_ID_DESC(SPDK_NVME_NIDT_UUID, &ns->opts.uuid, sizeof(ns->opts.uuid));
|
||||
|
||||
/*
|
||||
* The list is automatically 0-terminated because controller to host buffers in
|
||||
* admin commands always get zeroed in nvmf_ctrlr_process_admin_cmd().
|
||||
* The list is automatically 0-terminated, both in the temporary buffer
|
||||
* used by nvmf_ctrlr_identify(), and the eventual iov destination -
|
||||
* controller to host buffers in admin commands always get zeroed in
|
||||
* nvmf_ctrlr_process_admin_cmd().
|
||||
*/
|
||||
|
||||
#undef ADD_ID_DESC
|
||||
@ -2894,12 +2896,15 @@ nvmf_ctrlr_identify(struct spdk_nvmf_request *req)
|
||||
struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd;
|
||||
struct spdk_nvme_cpl *rsp = &req->rsp->nvme_cpl;
|
||||
struct spdk_nvmf_subsystem *subsystem = ctrlr->subsys;
|
||||
int ret = SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
|
||||
char tmpbuf[SPDK_NVME_IDENTIFY_BUFLEN] = "";
|
||||
struct copy_iovs_ctx copy_ctx;
|
||||
|
||||
if (req->data == NULL || req->length < SPDK_NVME_IDENTIFY_BUFLEN) {
|
||||
SPDK_DEBUGLOG(nvmf, "identify command with invalid buffer\n");
|
||||
rsp->status.sct = SPDK_NVME_SCT_GENERIC;
|
||||
rsp->status.sc = SPDK_NVME_SC_INVALID_FIELD;
|
||||
return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
cns = cmd->cdw10_bits.identify.cns;
|
||||
@ -2910,24 +2915,41 @@ nvmf_ctrlr_identify(struct spdk_nvmf_request *req)
|
||||
goto invalid_cns;
|
||||
}
|
||||
|
||||
/*
|
||||
* We must use a temporary buffer: it's entirely possible the out buffer
|
||||
* is split across more than one IOV.
|
||||
*/
|
||||
_init_copy_iovs_ctx(©_ctx, req->iov, req->iovcnt);
|
||||
|
||||
switch (cns) {
|
||||
case SPDK_NVME_IDENTIFY_NS:
|
||||
return spdk_nvmf_ctrlr_identify_ns(ctrlr, cmd, rsp, req->data);
|
||||
ret = spdk_nvmf_ctrlr_identify_ns(ctrlr, cmd, rsp, (void *)&tmpbuf);
|
||||
break;
|
||||
case SPDK_NVME_IDENTIFY_CTRLR:
|
||||
return spdk_nvmf_ctrlr_identify_ctrlr(ctrlr, req->data);
|
||||
ret = spdk_nvmf_ctrlr_identify_ctrlr(ctrlr, (void *)&tmpbuf);
|
||||
break;
|
||||
case SPDK_NVME_IDENTIFY_ACTIVE_NS_LIST:
|
||||
return nvmf_ctrlr_identify_active_ns_list(subsystem, cmd, rsp, req->data);
|
||||
ret = nvmf_ctrlr_identify_active_ns_list(subsystem, cmd, rsp, (void *)&tmpbuf);
|
||||
break;
|
||||
case SPDK_NVME_IDENTIFY_NS_ID_DESCRIPTOR_LIST:
|
||||
return nvmf_ctrlr_identify_ns_id_descriptor_list(subsystem, cmd, rsp, req->data, req->length);
|
||||
ret = nvmf_ctrlr_identify_ns_id_descriptor_list(subsystem, cmd, rsp,
|
||||
tmpbuf, req->length);
|
||||
break;
|
||||
default:
|
||||
goto invalid_cns;
|
||||
}
|
||||
|
||||
if (ret == SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE) {
|
||||
_copy_buf_to_iovs(©_ctx, tmpbuf, sizeof(tmpbuf));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
invalid_cns:
|
||||
SPDK_DEBUGLOG(nvmf, "Identify command with unsupported CNS 0x%02x\n", cns);
|
||||
rsp->status.sct = SPDK_NVME_SCT_GENERIC;
|
||||
rsp->status.sc = SPDK_NVME_SC_INVALID_FIELD;
|
||||
return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
Loading…
Reference in New Issue
Block a user