Skip to content
  • Akira Takeuchi's avatar
    mm: ensure get_unmapped_area() returns higher address than mmap_min_addr · 3cbafaa7
    Akira Takeuchi authored
    
    
    commit 2afc745f3e3079ab16c826be4860da2529054dd2 upstream.
    
    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().
    
    Note: The first and third chunk of my patch, which changes "len" check,
    are for more precise check using mmap_min_addr, and not for solving the
    above problem.
    
    [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: default avatarAkira Takeuchi <takeuchi.akr@jp.panasonic.com>
    Signed-off-by: default avatarKiyoshi Owada <owada.kiyoshi@jp.panasonic.com>
    Reviewed-by: default avatarNaoya Horiguchi <n-horiguchi@ah.jp.nec.com>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    3cbafaa7