nvmf: fix heap corruption of Reservation Report command
We should use `ns->registrants` to count the number of registered controllers(REGCTL) for Reservation Report command, as `subsystem->ctrlrs` only list current active sessions(controllers). Also use the output data buffer directly so that we don't need to calloc/free during the process of Reservation Report command. Fix #1928 Change-Id: I650224b751a08416208b8a504b82debff31e92fd Signed-off-by: Changpeng Liu <changpeng.liu@intel.com> Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/7822 Community-CI: Broadcom CI Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: wanghailiang <hailiangx.e.wang@intel.com>
This commit is contained in:
parent
3ebf25e020
commit
6b372f419d
@ -2677,13 +2677,11 @@ nvmf_ns_reservation_report(struct spdk_nvmf_ns *ns,
|
|||||||
struct spdk_nvmf_request *req)
|
struct spdk_nvmf_request *req)
|
||||||
{
|
{
|
||||||
struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd;
|
struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd;
|
||||||
struct spdk_nvmf_subsystem *subsystem = ctrlr->subsys;
|
|
||||||
struct spdk_nvmf_ctrlr *ctrlr_tmp;
|
|
||||||
struct spdk_nvmf_registrant *reg, *tmp;
|
struct spdk_nvmf_registrant *reg, *tmp;
|
||||||
struct spdk_nvme_reservation_status_extended_data *status_data;
|
struct spdk_nvme_reservation_status_extended_data *status_data;
|
||||||
struct spdk_nvme_registered_ctrlr_extended_data *ctrlr_data;
|
struct spdk_nvme_registered_ctrlr_extended_data *ctrlr_data;
|
||||||
uint8_t *payload;
|
uint8_t *payload;
|
||||||
uint32_t len, count = 0;
|
uint32_t transfer_len, payload_len = 0;
|
||||||
uint32_t regctl = 0;
|
uint32_t regctl = 0;
|
||||||
uint8_t status = SPDK_NVME_SC_SUCCESS;
|
uint8_t status = SPDK_NVME_SC_SUCCESS;
|
||||||
|
|
||||||
@ -2701,19 +2699,11 @@ nvmf_ns_reservation_report(struct spdk_nvmf_ns *ns,
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get number of registerd controllers, one Host may have more than
|
/* Number of Dwords of the Reservation Status data structure to transfer */
|
||||||
* one controller based on different ports.
|
transfer_len = (cmd->cdw10 + 1) * sizeof(uint32_t);
|
||||||
*/
|
payload = req->data;
|
||||||
TAILQ_FOREACH(ctrlr_tmp, &subsystem->ctrlrs, link) {
|
|
||||||
reg = nvmf_ns_reservation_get_registrant(ns, &ctrlr_tmp->hostid);
|
|
||||||
if (reg) {
|
|
||||||
regctl++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
len = sizeof(*status_data) + sizeof(*ctrlr_data) * regctl;
|
if (transfer_len < sizeof(struct spdk_nvme_reservation_status_extended_data)) {
|
||||||
payload = calloc(1, len);
|
|
||||||
if (!payload) {
|
|
||||||
status = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR;
|
status = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@ -2721,23 +2711,25 @@ nvmf_ns_reservation_report(struct spdk_nvmf_ns *ns,
|
|||||||
status_data = (struct spdk_nvme_reservation_status_extended_data *)payload;
|
status_data = (struct spdk_nvme_reservation_status_extended_data *)payload;
|
||||||
status_data->data.gen = ns->gen;
|
status_data->data.gen = ns->gen;
|
||||||
status_data->data.rtype = ns->rtype;
|
status_data->data.rtype = ns->rtype;
|
||||||
status_data->data.regctl = regctl;
|
|
||||||
status_data->data.ptpls = ns->ptpl_activated;
|
status_data->data.ptpls = ns->ptpl_activated;
|
||||||
|
payload_len += sizeof(struct spdk_nvme_reservation_status_extended_data);
|
||||||
|
|
||||||
TAILQ_FOREACH_SAFE(reg, &ns->registrants, link, tmp) {
|
TAILQ_FOREACH_SAFE(reg, &ns->registrants, link, tmp) {
|
||||||
assert(count <= regctl);
|
payload_len += sizeof(struct spdk_nvme_registered_ctrlr_extended_data);
|
||||||
|
if (payload_len > transfer_len) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ctrlr_data = (struct spdk_nvme_registered_ctrlr_extended_data *)
|
ctrlr_data = (struct spdk_nvme_registered_ctrlr_extended_data *)
|
||||||
(payload + sizeof(*status_data) + sizeof(*ctrlr_data) * count);
|
(payload + sizeof(*status_data) + sizeof(*ctrlr_data) * regctl);
|
||||||
/* Set to 0xffffh for dynamic controller */
|
/* Set to 0xffffh for dynamic controller */
|
||||||
ctrlr_data->cntlid = 0xffff;
|
ctrlr_data->cntlid = 0xffff;
|
||||||
ctrlr_data->rcsts.status = (ns->holder == reg) ? true : false;
|
ctrlr_data->rcsts.status = (ns->holder == reg) ? true : false;
|
||||||
ctrlr_data->rkey = reg->rkey;
|
ctrlr_data->rkey = reg->rkey;
|
||||||
spdk_uuid_copy((struct spdk_uuid *)ctrlr_data->hostid, ®->hostid);
|
spdk_uuid_copy((struct spdk_uuid *)ctrlr_data->hostid, ®->hostid);
|
||||||
count++;
|
regctl++;
|
||||||
}
|
}
|
||||||
|
status_data->data.regctl = regctl;
|
||||||
memcpy(req->data, payload, spdk_min(len, (cmd->cdw10 + 1) * sizeof(uint32_t)));
|
|
||||||
free(payload);
|
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
req->rsp->nvme_cpl.status.sct = SPDK_NVME_SCT_GENERIC;
|
req->rsp->nvme_cpl.status.sct = SPDK_NVME_SCT_GENERIC;
|
||||||
|
Loading…
Reference in New Issue
Block a user