mmap syscall fails with errno 14

0

I was trying to do a syscall injection with MMAP on another process and it was failing. I noticed the syscall was executing properly, so the problem should be something else. I decided to run the syscall directly through the target program to make it more simple to understand. Unsurprisingly, it wasn't working either, and I don't really know why:

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/errno.h>

int main()
{
    void* addr = 0;
    size_t len = sysconf(_SC_PAGE_SIZE);
    int prot = PROT_EXEC | PROT_READ | PROT_WRITE;
    int flags = MAP_PRIVATE | MAP_ANON;
    int fd = -1;
    off_t offset = 0;
    
    void* alloc0 = mmap(addr, len, prot, flags, fd, offset); //this works
    void* alloc1 = syscall(__NR_mmap, addr, len, prot, flags, fd, offset); //this doesn't work

    printf("Alloc0: %p\n", alloc0);
    printf("Alloc1: %p\n", alloc1);
    printf("Errno:  %i\n", errno);

    return 0;
}

Output:

Alloc0: 0xf7fac000
Alloc1: 0xffffffff
Errno:  14

Why would the normal mmap work and the mmap syscall with the same parameters not work?
I am running Manjaro, and the program has been compiled with GCC on 32 bits. Also, when I compiled it in 64 bits it worked just fine, no error. Any ideas?

c++
c
linux
system-calls
mmap
asked on Stack Overflow Oct 31, 2020 by rdbo

1 Answer

2

The legacy __NR_mmap syscall on 32-bit (at least 32-bit x86 anyway) does not have that signature. It takes a single argument that's a pointer to a struct mmap_arg_struct32; see https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/sys_ia32.c?id=v5.9#n214. This syscall is deprecated since the mid to late 90s, and should not be used. Error number 14 is EFAULT and is reflecting that your first argument is not a valid pointer to such a struct.

The modern replacement is __NR_mmap2 and it takes arguments similar to the mmap function, except that offset is a 32-bit count of 4k units, rather than a direct offset. This allows addressing offsets up to 2^44 in magnitude.


User contributions licensed under CC BY-SA 3.0