You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MMAP_PAGE_ZERO personality标志工作原理及正确用法

问题原因

你写的测试代码触发段错误的核心原因是personality()的调用时机错误。
MMAP_PAGE_ZERO标志只会影响标志设置完成后,内核新加载的进程的内存映射规则,不会修改已经处于运行状态的当前进程的已有内存布局。你在main()函数里才调用这个接口时,当前进程的地址空间早已完成初始化,零页默认被内核标记为不可访问状态,后续修改personality标志不会回溯调整已经建立的内存映射,因此解引用空指针依然会触发段错误。
另外还有一个容易踩的坑:直接传入MMAP_PAGE_ZERO作为参数调用personality()会覆盖进程默认的personality配置,清除系统默认开启的兼容性标志,容易引发其他运行异常。

正确使用方式

MMAP_PAGE_ZERO必须在目标程序被内核加载前就完成设置,有两种常见的正确用法:

  • 命令行直接使用:通过setarch工具在启动程序前预置标志,不需要修改程序代码,执行命令setarch -Z ./your_program即可,其中-Z参数对应开启MMAP_PAGE_ZERO特性,setarch会先完成personality设置,再exec加载目标程序,内核加载程序时就会自动将零页映射为只读。
  • 代码内自实现:在代码中设置完标志后,通过exec族函数重新加载自身进程镜像,让内核在加载阶段应用标志,参考代码如下:
#include <stdio.h>
#include <sys/personality.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    // 首次启动时先设置personality再重载自身
    if (argc == 1) {
        // 先读取当前personality值,叠加标志避免覆盖默认配置
        int cur_persona = personality(0xffffffff);
        personality(cur_persona | MMAP_PAGE_ZERO);
        // 重新执行自身,传入参数标记已完成配置
        execl(argv[0], argv[0], "loaded", NULL);
        perror("execl failed");
        return 1;
    }

    // 重载后的进程零页已被映射为只读,可以正常读取
    int *null_ptr = 0;
    printf("零页起始值:%d\n", *null_ptr);
    return 0;
}
注意事项
  • 该特性属于SVr4兼容层功能,仅在x86等少数架构上生效,且只映射地址0开始的第一个标准内存页(通常为4KB)为只读,访问该范围外的低地址依然会触发段错误。
  • 部分开启了强制SMAP、特殊安全加固策略的内核版本可能会禁用这个特性,测试前需要确认对应内核配置是否支持。

内容的提问来源于stack exchange,提问作者mrn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 05:39:18