]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
nvme: Fix ctrl use-after-free during sysfs deletion
authorIsrael Rukshin <israelr@mellanox.com>
Tue, 24 Mar 2020 15:29:41 +0000 (17:29 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 1 Oct 2020 11:17:49 +0000 (13:17 +0200)
[ Upstream commit b780d7415aacec855e2f2370cbf98f918b224903 ]

In case nvme_sysfs_delete() is called by the user before taking the ctrl
reference count, the ctrl may be freed during the creation and cause the
bug. Take the reference as soon as the controller is externally visible,
which is done by cdev_device_add() in nvme_init_ctrl(). Also take the
reference count at the core layer instead of taking it on each transport
separately.

Signed-off-by: Israel Rukshin <israelr@mellanox.com>
Reviewed-by: Max Gurtovoy <maxg@mellanox.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Keith Busch <kbusch@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/nvme/host/core.c
drivers/nvme/host/fc.c
drivers/nvme/host/pci.c
drivers/nvme/host/rdma.c
drivers/nvme/host/tcp.c
drivers/nvme/target/loop.c

index 8247e58624c10cbfcc3f48a3e2aed3995f10fd2d..32cefbd80bdfb5ca89c57c6ab3ff1db4e24bc86b 100644 (file)
@@ -4082,6 +4082,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
        if (ret)
                goto out_release_instance;
 
+       nvme_get_ctrl(ctrl);
        cdev_init(&ctrl->cdev, &nvme_dev_fops);
        ctrl->cdev.owner = ops->module;
        ret = cdev_device_add(&ctrl->cdev, ctrl->device);
@@ -4100,6 +4101,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
 
        return 0;
 out_free_name:
+       nvme_put_ctrl(ctrl);
        kfree_const(ctrl->device->kobj.name);
 out_release_instance:
        ida_simple_remove(&nvme_instance_ida, ctrl->instance);
index dae050d1f814de57895020f48d8a142143bf889d..da801a14cd13dfd0e70d6ff3fdcfff5e30ec100f 100644 (file)
@@ -3171,10 +3171,7 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
                goto fail_ctrl;
        }
 
-       nvme_get_ctrl(&ctrl->ctrl);
-
        if (!queue_delayed_work(nvme_wq, &ctrl->connect_work, 0)) {
-               nvme_put_ctrl(&ctrl->ctrl);
                dev_err(ctrl->ctrl.device,
                        "NVME-FC{%d}: failed to schedule initial connect\n",
                        ctrl->cnum);
@@ -3199,6 +3196,7 @@ fail_ctrl:
 
        /* initiate nvme ctrl ref counting teardown */
        nvme_uninit_ctrl(&ctrl->ctrl);
+       nvme_put_ctrl(&ctrl->ctrl);
 
        /* Remove core ctrl ref. */
        nvme_put_ctrl(&ctrl->ctrl);
index a91433bdf5de4ce3763168186f35459066d05693..75f26d2ec64295e779ac57d29df763c6ada03c8f 100644 (file)
@@ -2850,7 +2850,6 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        dev_info(dev->ctrl.device, "pci function %s\n", dev_name(&pdev->dev));
 
        nvme_reset_ctrl(&dev->ctrl);
-       nvme_get_ctrl(&dev->ctrl);
        async_schedule(nvme_async_probe, dev);
 
        return 0;
index f9444272f861e0008cd0c39234718b3de6cb8877..abe4fe496d05c46bff559d3f6030486c001d8ebc 100644 (file)
@@ -2088,8 +2088,6 @@ static struct nvme_ctrl *nvme_rdma_create_ctrl(struct device *dev,
        dev_info(ctrl->ctrl.device, "new ctrl: NQN \"%s\", addr %pISpcs\n",
                ctrl->ctrl.opts->subsysnqn, &ctrl->addr);
 
-       nvme_get_ctrl(&ctrl->ctrl);
-
        mutex_lock(&nvme_rdma_ctrl_mutex);
        list_add_tail(&ctrl->list, &nvme_rdma_ctrl_list);
        mutex_unlock(&nvme_rdma_ctrl_mutex);
@@ -2099,6 +2097,7 @@ static struct nvme_ctrl *nvme_rdma_create_ctrl(struct device *dev,
 out_uninit_ctrl:
        nvme_uninit_ctrl(&ctrl->ctrl);
        nvme_put_ctrl(&ctrl->ctrl);
+       nvme_put_ctrl(&ctrl->ctrl);
        if (ret > 0)
                ret = -EIO;
        return ERR_PTR(ret);
index c782005ee99f9cc81d56b8695ece37af603bf5e2..6d7a813e7183abcc764a327c8287a771a3bf40f8 100644 (file)
@@ -2404,8 +2404,6 @@ static struct nvme_ctrl *nvme_tcp_create_ctrl(struct device *dev,
        dev_info(ctrl->ctrl.device, "new ctrl: NQN \"%s\", addr %pISp\n",
                ctrl->ctrl.opts->subsysnqn, &ctrl->addr);
 
-       nvme_get_ctrl(&ctrl->ctrl);
-
        mutex_lock(&nvme_tcp_ctrl_mutex);
        list_add_tail(&ctrl->list, &nvme_tcp_ctrl_list);
        mutex_unlock(&nvme_tcp_ctrl_mutex);
@@ -2415,6 +2413,7 @@ static struct nvme_ctrl *nvme_tcp_create_ctrl(struct device *dev,
 out_uninit_ctrl:
        nvme_uninit_ctrl(&ctrl->ctrl);
        nvme_put_ctrl(&ctrl->ctrl);
+       nvme_put_ctrl(&ctrl->ctrl);
        if (ret > 0)
                ret = -EIO;
        return ERR_PTR(ret);
index 11f5aea97d1b1f704d30897d6dc3e2f42d86a0a0..82b87a4c50f63095099f96fd58389fc415b4e612 100644 (file)
@@ -619,8 +619,6 @@ static struct nvme_ctrl *nvme_loop_create_ctrl(struct device *dev,
        dev_info(ctrl->ctrl.device,
                 "new ctrl: \"%s\"\n", ctrl->ctrl.opts->subsysnqn);
 
-       nvme_get_ctrl(&ctrl->ctrl);
-
        changed = nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_LIVE);
        WARN_ON_ONCE(!changed);
 
@@ -638,6 +636,7 @@ out_free_queues:
        kfree(ctrl->queues);
 out_uninit_ctrl:
        nvme_uninit_ctrl(&ctrl->ctrl);
+       nvme_put_ctrl(&ctrl->ctrl);
 out_put_ctrl:
        nvme_put_ctrl(&ctrl->ctrl);
        if (ret > 0)