When apple_nvme_reset_work() fails it queues anv->remove_work, whose callback apple_nvme_remove_dead_ctrl_work() unbinds the driver through device_release_driver(). The work is embedded in the devm-allocated apple_nvme, but apple_nvme_remove() only flushes ctrl.reset_work, so an external unbind while the work is pending frees anv through devres_release_all() before the callback runs, and it operates on freed memory. Fix this by not unbinding from a work item at all, mirroring commit c7c16c5b1967 ("nvme-pci: don't unbind the driver on reset failure"): on reset failure, disable the controller, mark the namespaces dead and leave the controller in the dead state instead of queueing the deferred unbind. The device stays bound and can be recovered by unbinding and rebinding the driver. apple_nvme_disable() is now passed shutdown=true, as in the final disable in apple_nvme_remove(), so entered requests are completed. Draining the work from apple_nvme_remove() is not an option: that path holds the device lock the callback blocks on, so waiting would deadlock. This issue was found by an in-house static analysis tool. Fixes: 5bd2927aceba ("nvme-apple: Add initial Apple SoC NVMe driver") Cc: stable@vger.kernel.org Co-developed-by: Song Li Signed-off-by: Song Li Signed-off-by: Fan Wu --- drivers/nvme/host/apple.c | 2 insertions(+), 15 deletions(-) --- a/drivers/nvme/host/apple.c +++ b/drivers/nvme/host/apple.c @@ -193,7 +193,6 @@ mempool_t *iod_mempool; struct nvme_ctrl ctrl; - struct work_struct remove_work; struct apple_nvme_queue adminq; struct apple_nvme_queue ioq; @@ -1224,20 +1223,9 @@ out: dev_warn(anv->ctrl.device, "Reset failure status: %d\n", ret); nvme_change_ctrl_state(&anv->ctrl, NVME_CTRL_DELETING); - nvme_get_ctrl(&anv->ctrl); - apple_nvme_disable(anv, false); + apple_nvme_disable(anv, true); nvme_mark_namespaces_dead(&anv->ctrl); - if (!queue_work(nvme_wq, &anv->remove_work)) - nvme_put_ctrl(&anv->ctrl); -} - -static void apple_nvme_remove_dead_ctrl_work(struct work_struct *work) -{ - struct apple_nvme *anv = - container_of(work, struct apple_nvme, remove_work); - - nvme_put_ctrl(&anv->ctrl); - device_release_driver(anv->dev); + nvme_change_ctrl_state(&anv->ctrl, NVME_CTRL_DEAD); } static int apple_nvme_reg_read32(struct nvme_ctrl *ctrl, u32 off, u32 *val) @@ -1531,7 +1519,6 @@ } INIT_WORK(&anv->ctrl.reset_work, apple_nvme_reset_work); - INIT_WORK(&anv->remove_work, apple_nvme_remove_dead_ctrl_work); spin_lock_init(&anv->lock); ret = apple_nvme_queue_alloc(anv, &anv->adminq); -- 2.39.5