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

为何启用ASLR后mmap匿名映射地址未随机化?(Ubuntu 16.04 x86_64)

如何让匿名mmap的映射地址在ASLR启用时实现随机化?

先还原你的场景:
你在最新版Ubuntu 16.04 x86_64上运行这段代码:

void main(int argc, char *argv[]) { 
    while(1) { 
        char *x = (char *)mmap(0, 1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 
        printf("%p\n", x); 
        munmap(x, 1000); 
    } 
}

结果输出全是同一个地址:0x7f02ca14c000 0x7f02ca14c000 ...,但你预期在ASLR全局启用、传入0作为地址提示的情况下,应该得到随机地址。

为什么会出现这种情况?

这不是ASLR没生效,而是内核为了优化内存分配效率,会优先复用刚刚释放的地址空间块。你的代码里刚调用munmap释放了1000字节的匿名映射,紧接着又申请同样大小的匿名映射,内核会直接把刚释放的地址重新分配给你,完全跳过随机地址的选择逻辑——毕竟复用现成的空闲块比重新找一个随机地址要高效得多,还能减少地址空间碎片化。

怎么让mmap返回随机地址?

你可以通过以下几种方式打破这种复用逻辑:

  1. 在munmap和mmap之间插入其他内存操作
    比如在释放后先做一次malloc/free,打乱内核的空闲地址空间列表,这样下一次mmap就不会优先拿到刚释放的地址:

    #include <stdio.h>
    #include <sys/mman.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[]) { 
        while(1) { 
            char *x = (char *)mmap(0, 1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 
            printf("%p\n", x); 
            munmap(x, 1000);
            // 插入malloc/free打乱地址空间
            char *tmp = malloc(1024);
            free(tmp);
        } 
        return 0;
    }
    
  2. 不要立刻释放已分配的映射
    比如每次申请后保留映射,直到积累到一定数量再批量释放,这样每次新申请的地址就会从不同的空闲区域选择:

    #include <stdio.h>
    #include <sys/mman.h>
    #include <stdlib.h>
    
    #define MAX_MAPS 10
    int main(int argc, char *argv[]) { 
        char *maps[MAX_MAPS];
        int count = 0;
        while(1) { 
            maps[count] = (char *)mmap(0, 1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 
            printf("%p\n", maps[count]); 
            count++;
            if (count >= MAX_MAPS) {
                // 批量释放
                for(int i=0; i<MAX_MAPS; i++) {
                    munmap(maps[i], 1000);
                }
                count = 0;
            }
        } 
        return 0;
    }
    
  3. 确认ASLR确实处于完全启用状态
    先检查系统的ASLR配置,执行命令:

    cat /proc/sys/kernel/randomize_va_space
    

    如果输出是2,说明ASLR完全启用;如果是1则是部分随机,0是关闭。如果不是2,可以通过以下命令临时开启(需要root权限):

    echo 2 > /proc/sys/kernel/randomize_va_space
    

补充说明

ASLR的作用是在进程启动时随机化整个地址空间的布局(比如栈、堆、库加载地址的起始位置),但它不会强制内核在每次内存分配时都选择完全随机的地址——内核的内存分配策略还是会优先考虑效率和减少碎片化,所以才会出现你看到的复用情况。上面的方法都是通过干扰这种复用逻辑,让内核不得不选择新的随机地址。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:14:20