diff options
author | Klaus Jensen <k.jensen@samsung.com> | 2022-11-10 07:59:44 +0100 |
---|---|---|
committer | Klaus Jensen <k.jensen@samsung.com> | 2022-12-01 08:44:52 +0100 |
commit | 3dbc1708ea37d03dd18ce498039e31d8565e673a (patch) | |
tree | 476c6cb356c4285f6d45191184f9d603635fc8c3 | |
parent | 433c71e494ec66a7455b8ef2e6b2b42118426e50 (diff) |
hw/nvme: fix aio cancel in flush
Make sure that iocb->aiocb is NULL'ed when cancelling.
Fix a potential use-after-free by removing the bottom half and enqueuing
the completion directly.
Fixes: 38f4ac65ac88 ("hw/nvme: reimplement flush to allow cancellation")
Reviewed-by: Keith Busch <kbusch@kernel.org>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
-rw-r--r-- | hw/nvme/ctrl.c | 21 |
1 files changed, 6 insertions, 15 deletions
diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 9bc56075f6..fede5af6af 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -3160,7 +3160,6 @@ typedef struct NvmeFlushAIOCB { BlockAIOCB common; BlockAIOCB *aiocb; NvmeRequest *req; - QEMUBH *bh; int ret; NvmeNamespace *ns; @@ -3176,6 +3175,7 @@ static void nvme_flush_cancel(BlockAIOCB *acb) if (iocb->aiocb) { blk_aio_cancel_async(iocb->aiocb); + iocb->aiocb = NULL; } } @@ -3185,6 +3185,8 @@ static const AIOCBInfo nvme_flush_aiocb_info = { .get_aio_context = nvme_get_aio_context, }; +static void nvme_do_flush(NvmeFlushAIOCB *iocb); + static void nvme_flush_ns_cb(void *opaque, int ret) { NvmeFlushAIOCB *iocb = opaque; @@ -3206,13 +3208,11 @@ static void nvme_flush_ns_cb(void *opaque, int ret) } out: - iocb->aiocb = NULL; - qemu_bh_schedule(iocb->bh); + nvme_do_flush(iocb); } -static void nvme_flush_bh(void *opaque) +static void nvme_do_flush(NvmeFlushAIOCB *iocb) { - NvmeFlushAIOCB *iocb = opaque; NvmeRequest *req = iocb->req; NvmeCtrl *n = nvme_ctrl(req); int i; @@ -3239,14 +3239,8 @@ static void nvme_flush_bh(void *opaque) return; done: - qemu_bh_delete(iocb->bh); - iocb->bh = NULL; - iocb->common.cb(iocb->common.opaque, iocb->ret); - qemu_aio_unref(iocb); - - return; } static uint16_t nvme_flush(NvmeCtrl *n, NvmeRequest *req) @@ -3258,7 +3252,6 @@ static uint16_t nvme_flush(NvmeCtrl *n, NvmeRequest *req) iocb = qemu_aio_get(&nvme_flush_aiocb_info, NULL, nvme_misc_cb, req); iocb->req = req; - iocb->bh = qemu_bh_new(nvme_flush_bh, iocb); iocb->ret = 0; iocb->ns = NULL; iocb->nsid = 0; @@ -3280,13 +3273,11 @@ static uint16_t nvme_flush(NvmeCtrl *n, NvmeRequest *req) } req->aiocb = &iocb->common; - qemu_bh_schedule(iocb->bh); + nvme_do_flush(iocb); return NVME_NO_COMPLETE; out: - qemu_bh_delete(iocb->bh); - iocb->bh = NULL; qemu_aio_unref(iocb); return status; |