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);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.