首页 > 解决方案 > mmap 系统调用失败并显示 errno 14

问题描述

我试图在另一个进程上使用 MMAP 进行系统调用注入,但它失败了。我注意到系统调用正常执行,所以问题应该是别的。我决定直接通过目标程序运行系统调用,以使其更易于理解。不出所料,它也不起作用,我真的不知道为什么:

#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;
}

输出:

Alloc0: 0xf7fac000
Alloc1: 0xffffffff
Errno:  14

为什么正常的 mmap 可以工作,而具有相同参数的 mmap 系统调用不能工作?
我正在运行 Manjaro,并且该程序已使用 32 位 GCC 编译。此外,当我以 64 位编译它时,它工作得很好,没有错误。有任何想法吗?

标签: c++clinuxsystem-callsmmap

解决方案


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.


推荐阅读