macOS下mmap无法分配可执行页面的原因及修复方法
问题原因
macOS 13启用了严格的W^X(写异或执行)安全防护机制,核心规则就是同一块内存不能同时拥有写权限(PROT_WRITE)和执行权限(PROT_EXEC)。你当前的mmap调用同时指定了这两个权限,直接违反了系统的安全策略,所以哪怕mmap返回了有效指针,实际访问时也会触发段错误。
修复方法
得按W^X的规则来,分两步操作内存:
- 先申请只有读写权限的匿名内存,把要执行的内容写进去;
- 用
mprotect把这块内存的权限改成执行+读权限,之后再执行里面的代码。
修改后的示例代码:
#include <sys/mman.h> #include <stddef.h> #include <stdio.h> #include <errno.h> int main() { size_t size = 100; // 第一步:申请仅读写权限的匿名内存 char* buf = (char*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (buf == MAP_FAILED) { perror("mmap 失败"); return 1; } // 往内存里写数据(如果是可执行代码,这里填对应的机器指令) *buf = 'a'; // 第二步:修改权限为执行+读 if (mprotect(buf, size, PROT_READ | PROT_EXEC) == -1) { perror("mprotect 失败"); munmap(buf, size); return 1; } // 现在可以执行这块内存里的代码了(示例只是存了字符,实际替换成指令即可) // 比如调用函数:((void(*)())buf)(); // 用完记得释放内存 munmap(buf, size); return 0; }
额外说明
如果是JIT这类需要动态修改代码的场景,可以先把权限改回读写,修改内容后再改回执行权限——但每次切换都得用mprotect,而且绝对不能同时开写和执行权限。macOS的这个W^X是系统强制规则,没法绕过,必须按这个流程来。
内容的提问来源于stack exchange,提问作者Mr User
相关产品推荐
相关产品推荐

