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?
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