Re: [block] general protection fault in lo_rw_aio
Bart Van Assche <[email protected]>
| Newsgroups | org.kernel.vger.linux-block |
|---|---|
| Message-ID | <[email protected]> |
On 8/21/26 5:46 AM, Tetsuo Handa wrote: > On 2026/08/03 22:34, Tetsuo Handa wrote: >> I am waiting for your response on >> "[PATCH v5] loop: Fix NULL pointer dereference in lo_rw_aio()" at >> https://lkml.kernel.org/r/[email protected] . > > You have never responded for 4 months since I first contacted you at > https://lkml.kernel.org/r/[email protected] . > Nobody being interested in this problem has caused multiple issues for linux-next tree. > Will you become responsive on this problem? Since I didn't like the proposed solution I took a look at this issue myself. If nobody objects I will integrate the patch below in my loop driver patch series. Bart. From: Bart Van Assche <[email protected]> Subject: [PATCH] loop: Freeze the request queue in __loop_clr_fd() When closing a loop device, lo_release() invokes __loop_clr_fd() when disk_openers(disk) == 0. However, disk_openers(disk) == 0 does not guarantee that all I/O submitted by loop_queue_rq() has completed. Asynchronous direct I/O requests submitted via io_uring or Linux AIO can remain in-flight while the device is closed, and worker threads may still be processing enqueued commands. If __loop_clr_fd() clears lo->lo_backing_file to NULL without freezing the request queue, in-flight commands may read a NULL backing file pointer or access backing structures after fput(), resulting in NULL pointer dereferences or use-after-free bugs. Fix this by freezing lo->lo_queue in __loop_clr_fd() before clearing lo->lo_backing_file and unfreezing the queue after updating the queue limits. Hold lo->lo_mutex before calling queue_limits_start_update() and blk_mq_freeze_queue() to follow the established lock ordering (&lo->lo_mutex -> &q->limits_lock -> &q->q_usage_counter) and prevent circular lock dependencies with fs_reclaim. Fixes: 18048c1af783 ("loop: Fix a race between loop detach and loop open") Signed-off-by: Bart Van Assche <[email protected]> --- drivers/block/loop.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 619759cb28d2..de50f17e7d7a 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1182,29 +1182,27 @@ static void __loop_clr_fd(struct loop_device *lo) struct queue_limits lim; struct file *filp; gfp_t gfp = lo->old_gfp_mask; + unsigned int memflags; int err; mutex_lock(&lo->lo_mutex); + lim = queue_limits_start_update(lo->lo_queue); + memflags = blk_mq_freeze_queue(lo->lo_queue); filp = lo->lo_backing_file; lo->lo_backing_file = NULL; - mutex_unlock(&lo->lo_mutex); lo->lo_device = NULL; lo->lo_offset = 0; lo->lo_sizelimit = 0; memset(lo->lo_file_name, 0, LO_NAME_SIZE); - /* - * Reset the block size to the default. - * - * No queue freezing needed because this is called from the final - * ->release call only, so there can't be any outstanding I/O. - */ - lim = queue_limits_start_update(lo->lo_queue); + /* Reset the block size to the default. */ lim.logical_block_size = SECTOR_SIZE; lim.physical_block_size = SECTOR_SIZE; lim.io_min = SECTOR_SIZE; queue_limits_commit_update(lo->lo_queue, &lim); + blk_mq_unfreeze_queue(lo->lo_queue, memflags); + mutex_unlock(&lo->lo_mutex); invalidate_disk(lo->lo_disk); loop_sysfs_exit(lo);