
Coverity complains about a possible memory corruption in the nvme_ns_attach and _detach functions. While we should not (famous last words) be able to reach this function without nsid having previously been validated, this is still an open door for future misuse. Make Coverity and maintainers happy by asserting that the index into the array is valid. Also, while not detected by Coverity (yet), add an assert in nvme_subsys_ns and nvme_subsys_register_ns as well since a similar issue is exists there. Fixes: 037953b5b299 ("hw/block/nvme: support namespace detach") Fixes: CID 1450757 Fixes: CID 1450758 Cc: Minwoo Im <minwoo.im.dev@gmail.com> Signed-off-by: Klaus Jensen <k.jensen@samsung.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
120 lines
2.7 KiB
C
120 lines
2.7 KiB
C
/*
|
|
* QEMU NVM Express Subsystem: nvme-subsys
|
|
*
|
|
* Copyright (c) 2021 Minwoo Im <minwoo.im.dev@gmail.com>
|
|
*
|
|
* This code is licensed under the GNU GPL v2. Refer COPYING.
|
|
*/
|
|
|
|
#include "qemu/units.h"
|
|
#include "qemu/osdep.h"
|
|
#include "qemu/uuid.h"
|
|
#include "qemu/iov.h"
|
|
#include "qemu/cutils.h"
|
|
#include "qapi/error.h"
|
|
#include "hw/qdev-properties.h"
|
|
#include "hw/qdev-core.h"
|
|
#include "hw/block/block.h"
|
|
#include "block/aio.h"
|
|
#include "block/accounting.h"
|
|
#include "sysemu/sysemu.h"
|
|
#include "hw/pci/pci.h"
|
|
#include "nvme.h"
|
|
#include "nvme-subsys.h"
|
|
|
|
int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp)
|
|
{
|
|
NvmeSubsystem *subsys = n->subsys;
|
|
int cntlid;
|
|
|
|
for (cntlid = 0; cntlid < ARRAY_SIZE(subsys->ctrls); cntlid++) {
|
|
if (!subsys->ctrls[cntlid]) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (cntlid == ARRAY_SIZE(subsys->ctrls)) {
|
|
error_setg(errp, "no more free controller id");
|
|
return -1;
|
|
}
|
|
|
|
subsys->ctrls[cntlid] = n;
|
|
|
|
return cntlid;
|
|
}
|
|
|
|
int nvme_subsys_register_ns(NvmeNamespace *ns, Error **errp)
|
|
{
|
|
NvmeSubsystem *subsys = ns->subsys;
|
|
NvmeCtrl *n;
|
|
uint32_t nsid = nvme_nsid(ns);
|
|
int i;
|
|
|
|
assert(nsid && nsid <= NVME_SUBSYS_MAX_NAMESPACES);
|
|
|
|
if (subsys->namespaces[nsid]) {
|
|
error_setg(errp, "namespace %d already registerd to subsy %s",
|
|
nvme_nsid(ns), subsys->parent_obj.id);
|
|
return -1;
|
|
}
|
|
|
|
subsys->namespaces[nsid] = ns;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(subsys->ctrls); i++) {
|
|
n = subsys->ctrls[i];
|
|
|
|
if (n && nvme_register_namespace(n, ns, errp)) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void nvme_subsys_setup(NvmeSubsystem *subsys)
|
|
{
|
|
const char *nqn = subsys->params.nqn ?
|
|
subsys->params.nqn : subsys->parent_obj.id;
|
|
|
|
snprintf((char *)subsys->subnqn, sizeof(subsys->subnqn),
|
|
"nqn.2019-08.org.qemu:%s", nqn);
|
|
}
|
|
|
|
static void nvme_subsys_realize(DeviceState *dev, Error **errp)
|
|
{
|
|
NvmeSubsystem *subsys = NVME_SUBSYS(dev);
|
|
|
|
nvme_subsys_setup(subsys);
|
|
}
|
|
|
|
static Property nvme_subsystem_props[] = {
|
|
DEFINE_PROP_STRING("nqn", NvmeSubsystem, params.nqn),
|
|
DEFINE_PROP_END_OF_LIST(),
|
|
};
|
|
|
|
static void nvme_subsys_class_init(ObjectClass *oc, void *data)
|
|
{
|
|
DeviceClass *dc = DEVICE_CLASS(oc);
|
|
|
|
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
|
|
|
dc->realize = nvme_subsys_realize;
|
|
dc->desc = "Virtual NVMe subsystem";
|
|
|
|
device_class_set_props(dc, nvme_subsystem_props);
|
|
}
|
|
|
|
static const TypeInfo nvme_subsys_info = {
|
|
.name = TYPE_NVME_SUBSYS,
|
|
.parent = TYPE_DEVICE,
|
|
.class_init = nvme_subsys_class_init,
|
|
.instance_size = sizeof(NvmeSubsystem),
|
|
};
|
|
|
|
static void nvme_subsys_register_types(void)
|
|
{
|
|
type_register_static(&nvme_subsys_info);
|
|
}
|
|
|
|
type_init(nvme_subsys_register_types)
|