在 Linux 上使用 mmap 分配地址零失败

Ben*_*erg 5 c linux mmap

我正在为 Linux 编写一个静态程序加载器,我正在读取 ELF 程序头并将段映射到内存。

我遇到过一个可执行文件,它假定其第一个段的虚拟地址为 0。我的内存映射失败,在地址分配虚拟页时出错0

我想知道是否可以在0用户空间的地址处分配所有内存。

请参阅此示例代码:

/*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;
}
Run Code Online (Sandbox Code Playgroud)

我用以下方法编译它:

gcc mmaptests.c
Run Code Online (Sandbox Code Playgroud)

这是它返回的内容:

$./a.out
mmap result 0xffffffffffffffff (errno Operation not permitted)
Run Code Online (Sandbox Code Playgroud)

我将很高兴获得任何见解。

谢谢B

PSk*_*cik 4

mmap如果您有权限,或者在具有 sysctl 设置的系统上vm.mmap_min_addr = 0(而不是默认的 65536),Linux 只会允许您访问第 0 页。

gcc mmaptests.c && sudo ./a.out
Run Code Online (Sandbox Code Playgroud)

应该让你:

mmap result (nil) (errno Success)
Run Code Online (Sandbox Code Playgroud)

根据https://wiki.debian.org/mmap_min_addr,16 位 Windows 应用程序的 WINE 需要vm.mmap_min_addr = 0以非 root 身份运行,旧版本的 QEMU 也需要这样。不过,即使在这些软件包的安装程序中,大多数发行版也不会这样做,因为通过故障使 NULL-deref 失败非常严重可取的。(64 KiB 还涵盖以 0 为基数的小型数组索引。)

您可以使用 或 来检查当前设置cat /proc/sys/vm/mmap_min_addr,或将其格式化为十六进制,printf '%#x\n' $(cat /proc/sys/vm/mmap_min_addr)

  • @BenHirschberg这似乎是一个内核策略,旨在防止用户空间利用内核代码/模块中的NULL取消引用错误:https://blogs.oracle.com/linux/much-ado-about-null%3a-exploiting-a -内核空取消引用-v2 (2认同)
  • @BenHirschberg 请参阅“man 7 功能”中的“CAP_SYS_RAWIO”。 (2认同)