diff options
Diffstat (limited to 'mm/vmalloc.c')
| -rw-r--r-- | mm/vmalloc.c | 16 | 
1 files changed, 13 insertions, 3 deletions
| diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 399f219544f7..9a8227afa073 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -34,6 +34,7 @@  #include <linux/llist.h>  #include <linux/bitops.h>  #include <linux/rbtree_augmented.h> +#include <linux/overflow.h>  #include <linux/uaccess.h>  #include <asm/tlbflush.h> @@ -3054,6 +3055,7 @@ finished:   * @vma:		vma to cover   * @uaddr:		target user address to start at   * @kaddr:		virtual address of vmalloc kernel memory + * @pgoff:		offset from @kaddr to start at   * @size:		size of map area   *   * Returns:	0 for success, -Exxx on failure @@ -3066,9 +3068,15 @@ finished:   * Similar to remap_pfn_range() (see mm/memory.c)   */  int remap_vmalloc_range_partial(struct vm_area_struct *vma, unsigned long uaddr, -				void *kaddr, unsigned long size) +				void *kaddr, unsigned long pgoff, +				unsigned long size)  {  	struct vm_struct *area; +	unsigned long off; +	unsigned long end_index; + +	if (check_shl_overflow(pgoff, PAGE_SHIFT, &off)) +		return -EINVAL;  	size = PAGE_ALIGN(size); @@ -3082,8 +3090,10 @@ int remap_vmalloc_range_partial(struct vm_area_struct *vma, unsigned long uaddr,  	if (!(area->flags & (VM_USERMAP | VM_DMA_COHERENT)))  		return -EINVAL; -	if (kaddr + size > area->addr + get_vm_area_size(area)) +	if (check_add_overflow(size, off, &end_index) || +	    end_index > get_vm_area_size(area))  		return -EINVAL; +	kaddr += off;  	do {  		struct page *page = vmalloc_to_page(kaddr); @@ -3122,7 +3132,7 @@ int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,  						unsigned long pgoff)  {  	return remap_vmalloc_range_partial(vma, vma->vm_start, -					   addr + (pgoff << PAGE_SHIFT), +					   addr, pgoff,  					   vma->vm_end - vma->vm_start);  }  EXPORT_SYMBOL(remap_vmalloc_range); |