Re: [syzbot] [squashfs?] UBSAN: shift-out-of-bounds in squashfs_bio_read
From: Phillip Lougher
Date: Tue Apr 08 2025 - 00:27:41 EST
On 07/04/2025 06:30, Phillip Lougher wrote:
Digging deeper into the reproducer, it turns out the reproducer is
forking multiple processes which after mounting the Squashfs filesystem,
issues a LOOP_SET_BLOCK_SIZE(r0, 0x4c09, 0x8000) ioctl on loopback
device /dev/loop0. Now, if this ioctl occurs at the same time another
process is in the process of mounting a Squashfs filesystem on
/dev/loop0, the failure occurs. The ioctl has to be issued in the
early part of squashfs_fill_super() before the superblock has been read.
When this happens, the following code in squashfs_fill_super() fails.
----
msblk->devblksize = sb_min_blocksize(sb, SQUASHFS_DEVBLK_SIZE);
msblk->devblksize_log2 = ffz(~msblk->devblksize);
----
sb_min_blocksize() returns 0, which means msblk->devblksize is set to 0.
CC'ing Luis Chamberlain <mcgrof@xxxxxxxxxx>
Doing some more digging, what has changed to cause this failure, is a
post 6.14 change in the behaviour of the LOOP_SET_BLOCK_SIZE ioctl.
Doing a git bisect, prior to commit 47dd67532303803a87f43195e088b3b4bcf0454d
Author: Luis Chamberlain <mcgrof@xxxxxxxxxx>
block/bdev: lift block size restrictions to 64k
Attempts to set the loopback device block size to 0x8000 (32768) failed.
After the above commit, such attempts succeed. Having done so, this
causes the above sb_min_blocksize(sb, SQUASHFS_DEVBLK_SIZE) to fail.
This may be an unanticipated side effect of the change.
Checking the kernel code six filesystems fail to check the return
result of sb_min_blocksize (isofs, gfs2, exfat, fat, squashfs and xfs),
and so will be affected by this change.
But notwithstanding the above, the failure to check the return result of
sb_min_blocksize() in Squashfs is a bug, and I will send a patch that
fixes this and the syzbot exploit. Hopefully this will be tomorrow.
Phillip
As a result, ffz(~msblk->devblksize) returns 64, and
msblk->devblksize_log2 is set to 64.
This subsequently causes the
UBSAN: shift-out-of-bounds in fs/squashfs/block.c:195:36
shift exponent 64 is too large for 64-bit type 'u64' (aka 'unsigned long long')
The fix is to check for a 0 return by sb_min_blocksize().
I'll send a patch tomorrow.
Phillip