为什么在 mmap PROT_READ 中等于 PROT_EXEC

Why in mmap PROT_READ equals PROT_EXEC

我尝试使用 mmap 函数分配一些具有只读访问权限的内存页。我打印 /proc/self/maps 来检查内存保护是否正常工作。尽管 mmap 的保护参数是 PROT_READ

,它还是这样显示的
 7fec0c585000-7fec0c785000 r-xp 00000000 00:00 0

这意味着当我要求内核分配一些只读内存页面时,它也将它们标记为可执行文件。

我做了一些其他测试,我意识到当我要求只写页时,PROT_WRITE没有PROT_READ,[=的输出20=] 文件是这样的:

7fec0c585000-7fec0c785000 -w-p 00000000 00:00 0 

这意味着除了前面的例子 PROT_READ 等同于 PROT_EXEC

同时调用 mmapPROT_WRITE|PROT_READ,也可以执行。

不知有没有办法映射一个只读,不可执行的内存页;还是可读写且不可执行的?


测试所在计算机的信息运行:

  1. Linux Arch 4.1.6-1-ARCH #1 SMP PREEMPT 8 月 17 日星期一 08:52:28 CEST 2015 x86_64 GNU/Linux

  2. 英特尔酷睿 i5-2310,x86_64

经过一些研究,我发现 Linux 仅在 GNU_STACK 程序头包含在 ELF 程序头中时才激活内存保护。 内存保护是指使用处理器的 NX 位,因此内存页可以标记为不可执行。

据我了解,GNU_STACK 程序头旨在告诉内核您需要堆栈的一些特定属性,其中一个属性是不可执行的堆栈。看来,如果您不明确要求不可执行的堆栈,则所有标记为可读的 ELF 部分也将是可执行的。而且所有具有 mmap 的内存映射都具有相同的行为。

遗憾的是,没有足够的文档说明 GNU_STACK 的作用,并且 mmap 的文档没有指定它与 GNU_STACK 的连接以启用执行保护。

参考文献:

https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart

我在我的 Debian Jessie 中测试了这个问题。

我在一个特殊的地址映射了一个匿名区域,并打印了映射的内容,对应的权限形式:

PROT_READ               r--p
PROT_WRITE              -w-p
PROT_EXEC               --xp
PROT_READ|PROT_WRITE    rw-p
PROT_READ|PROT_EXEC     r-xp

我不测试 PROT_WRITE | PROT_EXEC ...,因为 pax/grsecurity 防止创建可写和可执行映射。

测试信息:
Linux 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt17-1 (2015-09-26) x86_64 GNU/Linux
英特尔 i7,x86_64