7.3-stable review patch. If anyone has any objections, please let me know. ------------------ From: Kyle Zeng commit 37e425460b7c41687e51e3254b1eb1d799da9614 upstream. io_wq_cancel_tw_create() inspects cb->func after calling io_worker_cancel_cb(). For an existing worker, that call can drop the last worker reference and wake io_worker_exit(). If the canceling task is preempted, the worker can be unlinked and freed by kfree_rcu() before the callback function is inspected. KASAN reports a slab-use-after-free read in this path. Save whether the callback belongs to an unpublished continuation worker while its reference is still held, then use the saved result for the conditional free. This preserves the existing accounting and frees only the worker allocated for the canceled continuation. Fixes: e6db6f9398da ("io_uring/io-wq: only free worker if it was allocated for creation") Cc: stable@vger.kernel.org Signed-off-by: Kyle Zeng Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- io_uring/io-wq.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) --- a/io_uring/io-wq.c +++ b/io_uring/io-wq.c @@ -1424,14 +1424,16 @@ static void io_wq_cancel_tw_create(struc while ((cb = task_work_cancel_match(wq->task, io_task_work_match, wq)) != NULL) { struct io_worker *worker; + bool free_worker; worker = container_of(cb, struct io_worker, create_work); - io_worker_cancel_cb(worker); /* * Only the worker continuation helper has worker allocated and - * hence needs freeing. + * hence needs freeing. Save this before dropping its reference. */ - if (cb->func == create_worker_cont) + free_worker = cb->func == create_worker_cont; + io_worker_cancel_cb(worker); + if (free_worker) kfree(worker); } }