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

旧版Linux(内核<4.17)下安全映射共享内存至固定地址的方法

低内核版本下安全映射共享内存到固定地址的方案

针对Linux内核版本低于4.17、无法使用MAP_FIXED_NOREPLACE的场景,有几种相对安全的方式实现共享内存固定地址映射,避免直接用MAP_FIXED覆盖现有有效映射的风险:

  • 先探测地址可用性再执行固定映射
    先调用不带MAP_FIXED标志的mmap(),将目标地址作为addr参数传入(仅作为地址提示)。如果返回值等于目标地址,说明该地址当前处于空闲状态。此时再调用带MAP_FIXED的mmap(),将共享内存映射到该地址即可。
    注意:这种方法存在竞态窗口——探测操作和正式映射之间,其他进程可能抢占该地址。如果由父进程先创建共享内存并完成映射,子进程再继承或跟进映射,竞态风险会大幅降低。
    示例代码片段:

    #include <sys/mman.h>
    #include <unistd.h>
    
    void *target_addr = (void *)0x12340000;
    size_t shm_size = 4096 * 4; // 按实际需求调整
    int shm_fd; // 已打开的共享内存文件描述符
    
    // 探测目标地址是否可用
    void *probe = mmap(target_addr, getpagesize(), PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (probe == target_addr) {
        // 地址可用,先释放探测用的匿名映射
        munmap(probe, getpagesize());
        // 正式映射共享内存到固定地址
        void *shm_addr = mmap(target_addr, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, shm_fd, 0);
        if (shm_addr == MAP_FAILED) {
            // 处理映射错误
            perror("mmap fixed failed");
        }
    } else {
        // 目标地址已被占用,释放探测映射并处理错误
        if (probe != MAP_FAILED) munmap(probe, getpagesize());
        fprintf(stderr, "Target address is already in use\n");
    }
    
  • 预留地址空间后再映射共享内存
    先通过匿名映射预留一块目标地址范围,权限设为PROT_NONE(不可访问),这样操作系统会将这块地址标记为已占用,不会分配给其他内存操作。之后再用MAP_FIXED将共享内存映射到这块预留地址,因为地址已被预留,不会覆盖现有有效映射。
    这种方法没有竞态问题,是多进程场景下最安全的方案。示例代码片段:

    #include <sys/mman.h>
    
    void *target_addr = (void *)0x12340000;
    size_t shm_size = 4096 * 4;
    int shm_fd;
    
    // 预留目标地址空间
    void *reserved = mmap(target_addr, shm_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (reserved != target_addr) {
        perror("Reserve address failed");
        return -1;
    }
    // 映射共享内存到预留地址
    void *shm_addr = mmap(target_addr, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, shm_fd, 0);
    if (shm_addr == MAP_FAILED) {
        perror("Map shared memory failed");
        munmap(reserved, shm_size);
        return -1;
    }
    
  • 调整进程地址空间布局
    通过编译或链接选项,让进程的默认代码段、数据段避开目标共享内存地址。比如使用链接器选项-Wl,--section-start=.data=0x20000000调整数据段起始地址,或者用setrlimit()限制进程地址空间大小,让目标地址落在未被使用的区域。这种方法兼容性稍差,需要根据目标系统的编译器、内核版本进行测试验证。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 05:42:47