[PATCH v2] loop: block changing lo_offset/lo_sizelimit on mounted device

Deepanshu Kartikey posted 1 patch 1 day, 5 hours ago
block/bdev.c              |  5 -----
drivers/block/loop.c      | 16 ++++++++++++++++
include/linux/blk_types.h |  5 +++++
3 files changed, 21 insertions(+), 5 deletions(-)
[PATCH v2] loop: block changing lo_offset/lo_sizelimit on mounted device
Posted by Deepanshu Kartikey 1 day, 5 hours ago
LOOP_SET_STATUS{64} allows changing lo_offset and shrinking
lo_sizelimit while a filesystem is mounted on the loop device.
This effectively mutates the data visible to the mounted filesystem,
which is equivalent to writing directly to the block device.

When CONFIG_BLK_DEV_WRITE_MOUNTED is disabled, direct writes to a
mounted block device are blocked. However, LOOP_SET_STATUS{64}
bypasses this protection because it modifies the loop configuration
through an ioctl rather than opening the block device for writing.

Fix this by checking bdev_writes_blocked() before allowing changes
to lo_offset or shrinking lo_sizelimit. If the loop device has
writes blocked, return -EBUSY. Increasing lo_sizelimit is still
allowed since growing the device is harmless and has legitimate
use cases such as online resize.

Move bdev_writes_blocked() from block/bdev.c to
include/linux/blk_types.h as a static inline function so it can
be used from the loop driver without exporting a symbol.

Suggested-by: Theodore Ts'o <tytso@mit.edu>
Reported-by: syzbot+fb32afec111a7d61b939@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=fb32afec111a7d61b939
Tested-by: syzbot+fb32afec111a7d61b939@syzkaller.appspotmail.com
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
v2:
  - Use #ifndef CONFIG_BLK_DEV_WRITE_MOUNTED instead of exporting
    bdev_writes_blocked(), as suggested by Ted Ts'o
  - Move bdev_writes_blocked() to include/linux/blk_types.h as
    static inline instead of exporting from block/bdev.c, as
    suggested by Christoph Hellwig
  - Allow increasing lo_sizelimit since growing the device is
    harmless, as pointed out by Christoph Hellwig
  - Remove spurious empty line
---
 block/bdev.c              |  5 -----
 drivers/block/loop.c      | 16 ++++++++++++++++
 include/linux/blk_types.h |  5 +++++
 3 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/block/bdev.c b/block/bdev.c
index ed022f8c48c7..e0bace1a6c27 100644
--- a/block/bdev.c
+++ b/block/bdev.c
@@ -860,11 +860,6 @@ void blkdev_put_no_open(struct block_device *bdev)
 	put_device(&bdev->bd_device);
 }
 
-static bool bdev_writes_blocked(struct block_device *bdev)
-{
-	return bdev->bd_writers < 0;
-}
-
 static void bdev_block_writes(struct block_device *bdev)
 {
 	bdev->bd_writers--;
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 0000913f7efc..34bbbf3bcb36 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1239,6 +1239,22 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
 		goto out_unlock;
 	}
 
+#ifndef CONFIG_BLK_DEV_WRITE_MOUNTED
+	/*
+	 * Changing lo_offset or shrinking lo_sizelimit on a mounted
+	 * device is equivalent to modifying the block device contents.
+	 * Block this if writes to the device are blocked.
+	 */
+	if ((lo->lo_offset != info->lo_offset ||
+	     (info->lo_sizelimit &&
+	      (lo->lo_sizelimit == 0 ||
+	       info->lo_sizelimit < lo->lo_sizelimit))) &&
+	    bdev_writes_blocked(lo->lo_device)) {
+		err = -EBUSY;
+		goto out_unlock;
+	}
+#endif
+
 	if (lo->lo_offset != info->lo_offset ||
 	    lo->lo_sizelimit != info->lo_sizelimit) {
 		size_changed = true;
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 8808ee76e73c..82ece8737b85 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -84,6 +84,11 @@ struct block_device {
 #define bdev_whole(_bdev) \
 	((_bdev)->bd_disk->part0)
 
+static inline bool bdev_writes_blocked(struct block_device *bdev)
+{
+	return bdev->bd_writers < 0;
+}
+
 #define dev_to_bdev(device) \
 	container_of((device), struct block_device, bd_device)
 
-- 
2.43.0
Re: [PATCH v2] loop: block changing lo_offset/lo_sizelimit on mounted device
Posted by Christoph Hellwig 1 day, 3 hours ago
On Tue, Mar 31, 2026 at 11:16:48AM +0530, Deepanshu Kartikey wrote:
> LOOP_SET_STATUS{64} allows changing lo_offset and shrinking
> lo_sizelimit while a filesystem is mounted on the loop device.
> This effectively mutates the data visible to the mounted filesystem,
> which is equivalent to writing directly to the block device.
> 
> When CONFIG_BLK_DEV_WRITE_MOUNTED is disabled, direct writes to a
> mounted block device are blocked. However, LOOP_SET_STATUS{64}
> bypasses this protection because it modifies the loop configuration
> through an ioctl rather than opening the block device for writing.
> 
> Fix this by checking bdev_writes_blocked() before allowing changes
> to lo_offset or shrinking lo_sizelimit. If the loop device has
> writes blocked, return -EBUSY. Increasing lo_sizelimit is still
> allowed since growing the device is harmless and has legitimate
> use cases such as online resize.
> 
> Move bdev_writes_blocked() from block/bdev.c to
> include/linux/blk_types.h as a static inline function so it can
> be used from the loop driver without exporting a symbol.

I still think this is a very bad idea for the reasons explained before.

And I would not be surprised if this breaks something in blktests or
xfstests as they heavily rely on resizing block devices.  Did you
do full runs of those?  Especially with xfs and btrfs for xfstests
as they do a lot more loop based tests?
Re: [PATCH v2] loop: block changing lo_offset/lo_sizelimit on mounted device
Posted by Theodore Tso 22 hours ago
On Tue, Mar 31, 2026 at 12:22:18AM -0700, Christoph Hellwig wrote:
> 
> And I would not be surprised if this breaks something in blktests or
> xfstests as they heavily rely on resizing block devices.  Did you
> do full runs of those?  Especially with xfs and btrfs for xfstests
> as they do a lot more loop based tests?

Do we expect people to seriously be running with
!CONFIG_BLK_DEV_WRITE_MOUNTED?  I view this as a syzkaller noise
suppression only.  As I mentioned earlier this option will very likely
break grub.

I do think that we need to have a way of disabling write access on a
per-super or per-file system type basis, eventually.  Perhaps we need
to get there sooner rather than later?  Would that make you happier?

					- Ted
Re: [PATCH v2] loop: block changing lo_offset/lo_sizelimit on mounted device
Posted by Christoph Hellwig 20 hours ago
On Tue, Mar 31, 2026 at 08:24:08AM -0400, Theodore Tso wrote:
> Do we expect people to seriously be running with
> !CONFIG_BLK_DEV_WRITE_MOUNTED? 

Yes, it's the only sane option.

> I view this as a syzkaller noise
> suppression only.  As I mentioned earlier this option will very likely
> break grub.

Yes, the horrible things grub does won't work with this.  But I thought
with EFI-based systems people had mostly stopped using the access
to the root file system misfeature in grub.  And a lot of specialized
distros seem to stop using grub entirely.