Search code examples
clinuxmmap

allocating address zero on Linux with mmap fails


I am writing a static program loader for Linux, I am reading ELF program headers and mapping the segments to the memory.

I have come across an executable which assumes that the virtual address of its first segment is at 0. My memory mapping fails, I get error allocating virtual page at address 0.

I wonder if it is possible to allocate at all memory at address 0 for the user-space.

See this example code:

/*mmaptests.c*/
#include <sys/mman.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

int main()
{
    void* p = mmap(0, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
    printf("mmap result %p (errno %s)\n",p,strerror(errno));
    return 0;
}

I compile it with:

gcc mmaptests.c

This is what it returns :

$./a.out
mmap result 0xffffffffffffffff (errno Operation not permitted)

I will be happy for any insights.

Thanks B


Solution

  • Linux will only let you mmap the 0-th page if you have privileges, or on a system with the sysctl setting vm.mmap_min_addr = 0 (instead of the default 65536).

    gcc mmaptests.c && sudo ./a.out
    

    should get you:

    mmap result (nil) (errno Success)
    

    According to https://wiki.debian.org/mmap_min_addr, WINE for 16-bit Windows applications needs vm.mmap_min_addr = 0, and so do old versions of QEMU to run as non-root. Most distros won't do that even in the installers for those packages, though, because making NULL-deref fail noisily by faulting is very desirable. (64 KiB also covers small array indexes from a base of 0.)

    You can check your current setting with cat /proc/sys/vm/mmap_min_addr, or to format as hex, printf '%#x\n' $(cat /proc/sys/vm/mmap_min_addr)