From 3370523d19f71d120050549e9c301d27718b8a85 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sat, 30 May 2026 22:48:17 +0900 Subject: [PATCH] loop: reject binding to procfs and sysfs files I noticed that /dev/loopX accepts pseudo files, for loop_validate_file() currently only checks: if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) return -EINVAL; and pseudo files are treated as S_ISREG(). Reading from pseudo files via /dev/loopX causes unexpected results, as it tries to repeatedly read the entire content up to the size visible to the "ls" command (padded with repeating data). # ls -l /sys/power/pm_test -rw-r--r-- 1 root root 4096 May 26 22:14 /sys/power/pm_test # cat /sys/power/pm_test | wc 1 6 48 # cat $(losetup -f --show /sys/power/pm_test) | wc 85 513 4096 Writing to pseudo files via /dev/loopX might also cause undesirable results. Therefore, explicitly reject binding to pseudo files on procfs and sysfs for now. Other filesystems can be appended as needed. There is another intention for this change. Currently, we are evaluating the possibility of calling drain_workqueue() from __loop_clr_fd() in order to address a NULL pointer dereference in lo_rw_aio() [1]. However, introducing drain_workqueue() into the loop teardown path where disk->open_mutex is held forms a circular locking dependency when a pseudo file that takes a global lock is specified as the backing store for the loop device. If drain_workqueue() is called from __loop_clr_fd(), an example of a circular locking dependency that involves system_transition_mutex and disk->open_mutex can be triggered by the following reproduction steps: # echo 7:0 > /sys/power/resume # losetup /dev/loop0 /sys/power/resume # cat /dev/loop0 > /dev/null # losetup -d /dev/loop0 Even if our final solution for [1] does not call drain_workqueue() with disk->open_mutex held, rejecting binding to pseudo files that confuse userspace programs is a standalone improvement. Link: https://syzkaller.appspot.com/bug?extid=cd8a9a308e879a4e2c28 [1] Analyzed-by: AI Mode in Google Search (no mail address) Signed-off-by: Tetsuo Handa --- drivers/block/loop.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 310de0463beb1..5e87e15c9d2f5 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -496,8 +496,15 @@ static int loop_validate_file(struct file *file, struct block_device *bdev) rmb(); f = l->lo_backing_file; } - if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) + if (S_ISBLK(inode->i_mode)) + return 0; + if (!S_ISREG(inode->i_mode)) return -EINVAL; + switch (inode->i_sb->s_magic) { + case PROC_SUPER_MAGIC: /* e.g. "losetup -f /proc/sys/kernel/version" */ + case SYSFS_MAGIC: /* e.g. "losetup -f /sys/power/state" */ + return -EINVAL; + } return 0; }