diff options
Diffstat (limited to 'fs/hugetlbfs/inode.c')
| -rw-r--r-- | fs/hugetlbfs/inode.c | 17 | 
1 files changed, 14 insertions, 3 deletions
| diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 8fe1b0aa2896..b9a254dcc0e7 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -108,6 +108,16 @@ static void huge_pagevec_release(struct pagevec *pvec)  	pagevec_reinit(pvec);  } +/* + * Mask used when checking the page offset value passed in via system + * calls.  This value will be converted to a loff_t which is signed. + * Therefore, we want to check the upper PAGE_SHIFT + 1 bits of the + * value.  The extra bit (- 1 in the shift value) is to take the sign + * bit into account. + */ +#define PGOFF_LOFFT_MAX \ +	(((1UL << (PAGE_SHIFT + 1)) - 1) <<  (BITS_PER_LONG - (PAGE_SHIFT + 1))) +  static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)  {  	struct inode *inode = file_inode(file); @@ -127,12 +137,13 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)  	vma->vm_ops = &hugetlb_vm_ops;  	/* -	 * Offset passed to mmap (before page shift) could have been -	 * negative when represented as a (l)off_t. +	 * page based offset in vm_pgoff could be sufficiently large to +	 * overflow a (l)off_t when converted to byte offset.  	 */ -	if (((loff_t)vma->vm_pgoff << PAGE_SHIFT) < 0) +	if (vma->vm_pgoff & PGOFF_LOFFT_MAX)  		return -EINVAL; +	/* must be huge page aligned */  	if (vma->vm_pgoff & (~huge_page_mask(h) >> PAGE_SHIFT))  		return -EINVAL; | 

