malloc分配的内存的保护标志是什么?

7
根据这个线程,由malloc分配的内存至少具有PROT_READ | PROT_EXEC,否则包含的函数将无法执行。

man malloc没有提到任何关于保护的内容,因此有这个问题。


你确定这是正确的线程吗?我在那里没有看到关于PROT_READ或PROT_EXEC的任何信息。我认为这两个与mmap有关。(请参阅http://pubs.opengroup.org/onlinepubs/007908799/xsh/mmap.html) - Mike Sherrill 'Cat Recall'
@Catcall,这就是我说的为什么malloc隐式返回的内存具有PROT_READPROT_EXEC,因为它不需要像mmap返回的内存一样进行mprotect(p, 1024, PROT_READ|PROT_EXEC)操作。 - Je Rog
4个回答

6

malloc()通常会返回可读可写的内存。一些架构(例如旧的x86)可能无法直接禁用执行权限,但这只是平台的不足之处。

如果您想要从分配的内存中执行代码,您需要明确给予执行权限,并且可能需要去除写权限,因为在某些系统上,在同一块内存上拥有写和执行权限被认为是潜在危险的(通常称为W^X)。

关于通过程序员分配的内存执行代码,已经有过几个其他的讨论主题:

在Linux上用C分配可执行内存
在标准C中,能否从栈中执行代码?


你有一台带有NX位的机器来测试吗? - Je Rog

6

malloc并不适合用于为代码分配内存的工具。你应该使用mmap,并根据系统上的严格安全策略,可能需要使用mprotect来更改权限。

以下是malloc不适合的原因:

  • 只有页面粒度才设置权限,但通过malloc获得的内存不太可能与页面对齐,因此您最终会在相邻的内存上设置权限,可能会破坏某些东西。
  • 如果在调用free之前不恢复旧权限,则可能会破坏malloc的内部结构。

关于权限仅以页面粒度设置,你的意思是void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); 返回的内存总是以页面为单位吗?虽然length参数似乎不能保证。 - Je Rog
1
@Je Rog:是的,mmap() 创建内存映射,具有页面粒度(除了在非 MMU 系统上)。 - ninjalj
1
“!mmu” 无法符合 POSIX(需要内存保护)要求。 - R.. GitHub STOP HELPING ICE
@Je Rog:它们将被映射,可以在Linux上查看/proc/<pid>/maps - ninjalj
长度将向页面大小的倍数取整。 - R.. GitHub STOP HELPING ICE
显示剩余3条评论

2
你可能需要在内存分配完成后自己调用 mprotect 来设置 PROT_EXEC 标志。 $ man mprotect

似乎不是,查看链接的段落,它并不涉及mprotect,这表明由malloc返回的内存已经具有PROT_EXEC - Je Rog
@Je Rog:好的-我很惊讶Linux默认为malloc分配的内存设置了PROT_EXEC,可能其他操作系统采取了更为防御的方法-如果您的问题仅适用于Linux,则应该将其标记为“linux”。 - Paul R
是的,这就是情况,我想知道设置了哪些其他标志,但是man malloc没有给出任何线索。此外,我不知道它是否特定于Linux,因此我认为添加该标签不合适。 - Je Rog
@Je Rog:最好不要做出任何假设,特别是如果你关注可移植性和未来的兼容性。 - Paul R
1
旧的x86 CPU没有页面的执行权限位,因此通常读取权限意味着执行权限。新的CPU有一个NX(非执行)位。 - ninjalj

0

malloc()库函数由C语言标准指定,因此在所有操作系统上都是相同的。内存保护是处理器和操作系统的功能,因此在Windows、Linux等系统上执行方式不同。

自malloc()被定义以来,其工作方式已经发生了变化。我记得大多数处理器不支持内存的单独“可执行”权限 - 如果它是可读的,那么它就是可执行的。许多嵌入式系统根本没有任何内存保护,所有内存都可以读取、写入和执行。在所有这些情况下,malloc()函数的工作方式都是相同的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接