From 3ec046ade16284d0f00e3f2fa7ba299d744d90fd Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Tue, 24 Sep 2019 11:23:30 +0100 Subject: [PATCH] nvme: Fix NULL ptr dereference For an admin command (get_feature and set_feature) the namespace is not set in the req. Instead, get it based on the command's nsid. --- hw/block/nvme.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index fda610f166..4446906177 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1454,12 +1454,12 @@ static uint16_t nvme_get_feature_timestamp(NvmeCtrl *n, NvmeCmd *cmd, static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) { - NvmeNamespace *ns = req->ns; - uint32_t dw10 = le32_to_cpu(cmd->cdw10); uint32_t dw11 = le32_to_cpu(cmd->cdw11); uint32_t result; + uint32_t nsid; + trace_nvme_getfeat(dw10); switch (dw10) { @@ -1476,7 +1476,13 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) result = cpu_to_le32(n->features.err_rec); break; case NVME_VOLATILE_WRITE_CACHE: - result = blk_enable_write_cache(ns->conf.blk); + nsid = le32_to_cpu(cmd->nsid); + if (unlikely(nsid == 0 || nsid > n->num_namespaces)) { + trace_nvme_err_invalid_ns(nsid, n->num_namespaces); + return NVME_INVALID_NSID | NVME_DNR; + } + + result = blk_enable_write_cache(n->namespaces[nsid - 1]->conf.blk); trace_nvme_getfeat_vwcache(result ? "enabled" : "disabled"); break; case NVME_NUMBER_OF_QUEUES: @@ -1530,11 +1536,11 @@ static uint16_t nvme_set_feature_timestamp(NvmeCtrl *n, NvmeCmd *cmd, static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) { - NvmeNamespace *ns = req->ns; - uint32_t dw10 = le32_to_cpu(cmd->cdw10); uint32_t dw11 = le32_to_cpu(cmd->cdw11); + uint32_t nsid; + trace_nvme_setfeat(dw10, dw11); switch (dw10) { @@ -1546,7 +1552,13 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) } break; case NVME_VOLATILE_WRITE_CACHE: - blk_set_enable_write_cache(ns->conf.blk, dw11 & 1); + nsid = le32_to_cpu(cmd->nsid); + if (unlikely(nsid == 0 || nsid > n->num_namespaces)) { + trace_nvme_err_invalid_ns(nsid, n->num_namespaces); + return NVME_INVALID_NSID | NVME_DNR; + } + + blk_set_enable_write_cache(n->namespaces[nsid - 1]->conf.blk, dw11 & 1); break; case NVME_NUMBER_OF_QUEUES: if (n->qs_created > 2) { -- 2.39.5