The the sum of two uint64_t integers, start and len, might overflow. This leads to bypassing the check in "start + len > i_size_read(bdev->bd_inode)", and passed to truncate_inode_pages_range() as the 3rd parameter. To fix this, also in accord with the patch 22dd6d356628bccb1a83e12212ec2934f4444e2c, the sum of these 2 integers are stored in another variable, and compared with start to make sure it will not overflow. Otherwise return -EINVAL properly. Signed-off-by: Changming Liu <liu.changm@xxxxxxxxxxxxxxxx> --- block/ioctl.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/block/ioctl.c b/block/ioctl.c index 127194b..4347d1f 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -207,7 +207,7 @@ static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode, unsigned long arg, unsigned long flags) { uint64_t range[2]; - uint64_t start, len; + uint64_t start, len, end; struct request_queue *q = bdev_get_queue(bdev); struct address_space *mapping = bdev->bd_inode->i_mapping; @@ -223,14 +223,17 @@ static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode, start = range[0]; len = range[1]; + end = start + len - 1; if (start & 511) return -EINVAL; if (len & 511) return -EINVAL; - - if (start + len > i_size_read(bdev->bd_inode)) + if (end >= (uint64_t)i_size_read(bdev->bd_inode)) return -EINVAL; + if(end < start) + return -EINVAL; + truncate_inode_pages_range(mapping, start, start + len - 1); return blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_KERNEL, flags); -- 2.7.4