Re: [PATCH] mm: Ensure get_unmapped_area() returns higher addressthan mmap_min_addr

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

On Wed, 23 Oct 2013 00:26:05 -0400
Naoya Horiguchi <n-horiguchi@xxxxxxxxxxxxx> wrote:

> Hi,
> 
> On Wed, Oct 23, 2013 at 11:46:53AM +0900, Akira Takeuchi wrote:
> > This patch fixes the problem that get_unmapped_area() can return illegal
> > address and result in failing mmap(2) etc.
> > 
> > In case that the address higher than PAGE_SIZE is set to
> > /proc/sys/vm/mmap_min_addr, the address lower than mmap_min_addr can be
> > returned by get_unmapped_area(), even if you do not pass any virtual
> > address hint (i.e. the second argument).
> > 
> > This is because the current get_unmapped_area() code does not take into
> > account mmap_min_addr.
> > 
> > This leads to two actual problems as follows:
> > 
> > 1. mmap(2) can fail with EPERM on the process without CAP_SYS_RAWIO,
> >    although any illegal parameter is not passed.
> > 
> > 2. The bottom-up search path after the top-down search might not work in
> >    arch_get_unmapped_area_topdown().
> > 
> > [How to reproduce]
> > 
> > 	--- test.c -------------------------------------------------
> > 	#include <stdio.h>
> > 	#include <unistd.h>
> > 	#include <sys/mman.h>
> > 	#include <sys/errno.h>
> > 
> > 	int main(int argc, char *argv[])
> > 	{
> > 		void *ret = NULL, *last_map;
> > 		size_t pagesize = sysconf(_SC_PAGESIZE);
> > 
> > 		do {
> > 			last_map = ret;
> > 			ret = mmap(0, pagesize, PROT_NONE,
> > 				MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
> > 	//		printf("ret=%p\n", ret);
> > 		} while (ret != MAP_FAILED);
> > 
> > 		if (errno != ENOMEM) {
> > 			printf("ERR: unexpected errno: %d (last map=%p)\n",
> > 			errno, last_map);
> > 		}
> > 
> > 		return 0;
> > 	}
> > 	---------------------------------------------------------------
> > 
> > 	$ gcc -m32 -o test test.c
> > 	$ sudo sysctl -w vm.mmap_min_addr=65536
> > 	vm.mmap_min_addr = 65536
> > 	$ ./test  (run as non-priviledge user)
> > 	ERR: unexpected errno: 1 (last map=0x10000)
> > 
> > Signed-off-by: Akira Takeuchi <takeuchi.akr@xxxxxxxxxxxxxxxx>
> > Signed-off-by: Kiyoshi Owada <owada.kiyoshi@xxxxxxxxxxxxxxxx>
> > ---
> >  mm/mmap.c |   10 +++++-----
> >  1 files changed, 5 insertions(+), 5 deletions(-)
> > 
> > diff --git a/mm/mmap.c b/mm/mmap.c
> > index 9d54851..362e5f1 100644
> > --- a/mm/mmap.c
> > +++ b/mm/mmap.c
> > @@ -1856,7 +1856,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
> >  	struct vm_area_struct *vma;
> >  	struct vm_unmapped_area_info info;
> >  
> > -	if (len > TASK_SIZE)
> > +	if (len > TASK_SIZE - mmap_min_addr)
> >  		return -ENOMEM;
> >  
> >  	if (flags & MAP_FIXED)
> 
> I feel that it looks clearer to fix this in round_hint_to_min(),
> with doing mmap_min_addr check in hint == NULL case.
> Does it work for you?

The current round_hint_to_min() code checks and adjusts just for
the hint address, not for "len". Also, it returns no error.

Do you mean adding "len" to the argument of round_hint_to_min()
and making round_hint_to_min() return any error ?


Regards,
Akira Takeuchi

> Thanks,
> Naoya Horiguchi
> 
> > @@ -1865,7 +1865,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
> >  	if (addr) {
> >  		addr = PAGE_ALIGN(addr);
> >  		vma = find_vma(mm, addr);
> > -		if (TASK_SIZE - len >= addr &&
> > +		if (TASK_SIZE - len >= addr && addr >= mmap_min_addr &&
> >  		    (!vma || addr + len <= vma->vm_start))
> >  			return addr;
> >  	}
> > @@ -1895,7 +1895,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
> >  	struct vm_unmapped_area_info info;
> >  
> >  	/* requested length too big for entire address space */
> > -	if (len > TASK_SIZE)
> > +	if (len > TASK_SIZE - mmap_min_addr)
> >  		return -ENOMEM;
> >  
> >  	if (flags & MAP_FIXED)
> > @@ -1905,14 +1905,14 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
> >  	if (addr) {
> >  		addr = PAGE_ALIGN(addr);
> >  		vma = find_vma(mm, addr);
> > -		if (TASK_SIZE - len >= addr &&
> > +		if (TASK_SIZE - len >= addr && addr >= mmap_min_addr &&
> >  				(!vma || addr + len <= vma->vm_start))
> >  			return addr;
> >  	}
> >  
> >  	info.flags = VM_UNMAPPED_AREA_TOPDOWN;
> >  	info.length = len;
> > -	info.low_limit = PAGE_SIZE;
> > +	info.low_limit = max(PAGE_SIZE, mmap_min_addr);
> >  	info.high_limit = mm->mmap_base;
> >  	info.align_mask = 0;
> >  	addr = vm_unmapped_area(&info);
> > -- 
> > 1.7.0.4
> > 
> > 
> > -- 
> > Akira Takeuchi <takeuchi.akr@xxxxxxxxxxxxxxxx>
> > 
> > --
> > To unsubscribe, send a message with 'unsubscribe linux-mm' in
> > the body to majordomo@xxxxxxxxx.  For more info on Linux MM,
> > see: http://www.linux-mm.org/ .
> > Don't email: <a href=mailto:"dont@xxxxxxxxx";> email@xxxxxxxxx </a>
> > 

-- 
Akira Takeuchi <takeuchi.akr@xxxxxxxxxxxxxxxx>

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@xxxxxxxxx.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@xxxxxxxxx";> email@xxxxxxxxx </a>




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]