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_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_nvme_reservation_status_extended_data *status_data;
|
||||
struct spdk_nvme_registered_ctrlr_extended_data *ctrlr_data;
|
||||
uint8_t *payload;
|
||||
uint32_t len, count = 0;
|
||||
uint32_t transfer_len, payload_len = 0;
|
||||
uint32_t regctl = 0;
|
||||
uint8_t status = SPDK_NVME_SC_SUCCESS;
|
||||
|
||||
@ -2701,19 +2699,11 @@ nvmf_ns_reservation_report(struct spdk_nvmf_ns *ns,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Get number of registerd controllers, one Host may have more than
|
||||
* one controller based on different ports.
|
||||
*/
|
||||
TAILQ_FOREACH(ctrlr_tmp, &subsystem->ctrlrs, link) {
|
||||
reg = nvmf_ns_reservation_get_registrant(ns, &ctrlr_tmp->hostid);
|
||||
if (reg) {
|
||||
regctl++;
|
||||
}
|
||||
}
|
||||
/* Number of Dwords of the Reservation Status data structure to transfer */
|
||||
transfer_len = (cmd->cdw10 + 1) * sizeof(uint32_t);
|
||||
payload = req->data;
|
||||
|
||||
len = sizeof(*status_data) + sizeof(*ctrlr_data) * regctl;
|
||||
payload = calloc(1, len);
|
||||
if (!payload) {
|
||||
if (transfer_len < sizeof(struct spdk_nvme_reservation_status_extended_data)) {
|
||||
status = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR;
|
||||
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->data.gen = ns->gen;
|
||||
status_data->data.rtype = ns->rtype;
|
||||
status_data->data.regctl = regctl;
|
||||
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) {
|
||||
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 *)
|
||||
(payload + sizeof(*status_data) + sizeof(*ctrlr_data) * count);
|
||||
(payload + sizeof(*status_data) + sizeof(*ctrlr_data) * regctl);
|
||||
/* Set to 0xffffh for dynamic controller */
|
||||
ctrlr_data->cntlid = 0xffff;
|
||||
ctrlr_data->rcsts.status = (ns->holder == reg) ? true : false;
|
||||
ctrlr_data->rkey = reg->rkey;
|
||||
spdk_uuid_copy((struct spdk_uuid *)ctrlr_data->hostid, ®->hostid);
|
||||
count++;
|
||||
regctl++;
|
||||
}
|
||||
|
||||
memcpy(req->data, payload, spdk_min(len, (cmd->cdw10 + 1) * sizeof(uint32_t)));
|
||||
free(payload);
|
||||
status_data->data.regctl = regctl;
|
||||
|
||||
exit:
|
||||
req->rsp->nvme_cpl.status.sct = SPDK_NVME_SCT_GENERIC;
|
||||
|
Loading…
Reference in New Issue
Block a user