]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
block: fix integer overflow in BLKSECDISCARD
authorAlexey Dobriyan <adobriyan@gmail.com>
Tue, 3 Sep 2024 19:48:19 +0000 (22:48 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 10 Oct 2024 10:00:21 +0000 (12:00 +0200)
[ Upstream commit 697ba0b6ec4ae04afb67d3911799b5e2043b4455 ]

I independently rediscovered

commit 22d24a544b0d49bbcbd61c8c0eaf77d3c9297155
block: fix overflow in blk_ioctl_discard()

but for secure erase.

Same problem:

uint64_t r[2] = {512, 18446744073709551104ULL};
ioctl(fd, BLKSECDISCARD, r);

will enter near infinite loop inside blkdev_issue_secure_erase():

a.out: attempt to access beyond end of device
loop0: rw=5, sector=3399043073, nr_sectors = 1024 limit=2048
bio_check_eod: 3286214 callbacks suppressed

Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Link: https://lore.kernel.org/r/9e64057f-650a-46d1-b9f7-34af391536ef@p183
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
block/ioctl.c

index d570e16958961e1e4eb694ecb57812f41f6458fd..4515d4679eefd6cf35b16b63038b6f454d6b6d84 100644 (file)
@@ -126,7 +126,7 @@ static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode,
                return -EINVAL;
 
        filemap_invalidate_lock(bdev->bd_mapping);
-       err = truncate_bdev_range(bdev, mode, start, start + len - 1);
+       err = truncate_bdev_range(bdev, mode, start, end - 1);
        if (err)
                goto fail;
 
@@ -163,7 +163,7 @@ fail:
 static int blk_ioctl_secure_erase(struct block_device *bdev, blk_mode_t mode,
                void __user *argp)
 {
-       uint64_t start, len;
+       uint64_t start, len, end;
        uint64_t range[2];
        int err;
 
@@ -178,11 +178,12 @@ static int blk_ioctl_secure_erase(struct block_device *bdev, blk_mode_t mode,
        len = range[1];
        if ((start & 511) || (len & 511))
                return -EINVAL;
-       if (start + len > bdev_nr_bytes(bdev))
+       if (check_add_overflow(start, len, &end) ||
+           end > bdev_nr_bytes(bdev))
                return -EINVAL;
 
        filemap_invalidate_lock(bdev->bd_mapping);
-       err = truncate_bdev_range(bdev, mode, start, start + len - 1);
+       err = truncate_bdev_range(bdev, mode, start, end - 1);
        if (!err)
                err = blkdev_issue_secure_erase(bdev, start >> 9, len >> 9,
                                                GFP_KERNEL);