On 2/26/19 3:51 AM, Carlos Maiolino wrote:
> guard_bio_eod() can truncate a segment in bio to allow it to do IO on
> odd last sectors of a device.
>
> It already checks if the IO starts past EOD, but it does not consider
> the possibility of an IO request starting within device boundaries can
> contain more than one segment past EOD.
>
> In such cases, truncated_bytes can be bigger than PAGE_SIZE, and will
> underflow bvec->bv_len.
>
> Fix this by checking if truncated_bytes is lower than PAGE_SIZE.
>
> This situation has been found on filesystems such as isofs and vfat,
> which doesn't check the device size before mount, if the device is
> smaller than the filesystem itself, a readahead on such filesystem,
> which spans EOD, can trigger this situation, leading a call to
> zero_user() with a wrong size possibly corrupting memory.
>
> I didn't see any crash, or didn't let the system run long enough to
> check if memory corruption will be hit somewhere, but adding
> instrumentation to guard_bio_end() to check truncated_bytes size, was
> enough to see the error.
>
> The following script can trigger the error.
>
> MNT=/mnt
> IMG=./DISK.img
> DEV=/dev/loop0
>
> mkfs.vfat $IMG
> mount $IMG $MNT
> cp -R /etc $MNT &> /dev/null
> umount $MNT
>
> losetup -D
>
> losetup --find --show --sizelimit 16247280 $IMG
> mount $DEV $MNT
>
> find $MNT -type f -exec cat {} + >/dev/null
>
> Kudos to Eric Sandeen for coming up with the reproducer above
>
> Changelog:
>
> V2: Compare truncated_bytes agains bvec->bv_len instead of
> PAGE_SIZE
Applied - note I snipped your changelog, that should go below the ---
lines to not end up in the commit message.
--
Jens Axboe