2012-02-28 67 views
5

我期望由于地址空间布局随机化(ALSR),从另一个进程分叉的进程在调用mmap时将返回不同的地址。但是,当我发现,情况并非如此。我为此做了以下测试程序。所有由malloc返回的地址对父母和孩子完全相同。 注意,mallocCL1CL2PL1PL2内部使用mmap,因为他们是大块。地址空间布局随机化(ALSR)和mmap

所以,我的问题是,为什么mmap即使存在ALSR也不会返回不同的地址。也许是因为这里随机化的种子对于原始和分叉过程是相同的。还是有其他原因吗?

int main() 
{ 
    pid = fork(); 

    if (pid == 0)    // child 
    { 
    void * c1 = malloc(4096); 
    void * c2 = malloc(4096); 

    void * cl1 = malloc((long)512e3); // internally uses mmap 
    void * cl2 = malloc((long)512e3); // internally uses mmap 

    printf("c1 = %p, c2 = %p, cl1 = %p, cl2 = %p!\n", c1, c2, cl1, cl2); 
    } 
    else 
    { 
    void * p1 = malloc(4096); 
    void * p2 = malloc(4096); 

    void * pl1 = malloc((long)512e3); // internally uses mmap 
    void * pl2 = malloc((long)512e3); // internally uses mmap 

    printf("p1 = %p, p2 = %p, pl1 = %p, pl2 = %p!\n", p1, p2, pl1, pl2); 
    } 

    return 0; 
} 
+0

我不确定ASLR要求'mmap'返回不同的地址;它只是意味着它*可能*返回不同的。也许(只是一个猜测!)它是由'execve'触发的而不是'fork'触发的。当然,如果我连续两次启动程序,我会得到不同的地址。而这可能会随着未来的内核或者SELinux启用的内核而改变...... – 2012-02-28 16:10:01

+2

你可能会觉得这很有用:http://xorl.wordpress.com/2011/01/16/linux-kernel-aslr-implementation/ – Necrolis 2012-02-28 16:14:58

+0

@巴西尔:当然,你会得到不同的地址为每次运行,但一次运行,这两个进程(父母和孩子)的地址有没有不同? – MetallicPriest 2012-02-28 16:15:22

回答

4

你不能再随机孩子的地址空间 - 所有的指针将不得不被感动了,这是技术上是不可能的(运行时环境甚至不知道你的数据的一部分是指针)。

因此,您所看到的结果是预期的,fork中的孩子在分岔时具有其父地址空间的精确副本,包括其虚拟地址布局。

您将需要调用exec*以获取新的地址空间布局。

$ cat t.c 
#include <unistd.h> 
#include <stdlib.h> 
#include <stdio.h> 

int main(int argc, char **argv) 
{ 
    printf("%p\n", malloc((long)512e3)); 
    if ((argc > 1) && fork()) { 
     execl("./a.out", "./a.out", NULL); 
    } 
    return 0; 
} 
$ gcc -Wall t.c 
$ ./a.out 1 
0x7f5bf6962010 
0x7f3483044010 
$ ./a.out 1 
0x7f1ce7462010 
0x7feb2adc2010 

(并确保/proc/sys/kernel/randomize_va_space是不是也为零。)

+0

OP似乎并不希望fork之前创建的映射更改地址,只是为了获得独立的随机地址之后的新映射。这在技术上不是不可能的,但正如我的回答所述,这是一个糟糕的主意。 – 2012-02-28 16:19:01

+0

所以,你的意思是每个未来的mmap,sbrk,malloc等都将返回父进程和子进程的相同地址? – MetallicPriest 2012-02-28 16:19:11

+1

@MetallicPriest:如果你按照完全相同的顺序执行它们,那么对于相同的数量,没有外部因素(资源限制,普通的OOM等),可能是使用普通的Linux内核。一些补丁可能存在随机化动态分配,但不是基本内核。有关更多信息,请参阅R ..的答案。 – Mat 2012-02-28 16:23:48

5

ASLR主要来自随机化的用户空间地址空间上的距离降低到堆栈,从重新建立了新的底部的距离预留空间到第一个mmap(这可能是动态链接器的映射)。任何进一步的随机化都会对虚拟内存空间造成严重的碎片化影响,因此会破坏需要大量编程的程序(例如,在32位机器上进行1-2 GB映射)。

我已经看到一些Linux发行版补丁内核对mmap返回的地址执行更多的随机化。他们中的一些甚至会给你映射重叠的空间保留给堆栈扩展,然后当堆栈增长时,它会破坏你的映射(导致一个巨大的安全漏洞,比任何非随机地址分配可能造成的大得多) 。远离这些黑客。

+0

所以我们可以假设分叉进程中的mmap不会总是返回与父进程相同的地址?对? – MetallicPriest 2012-02-28 16:21:24

+0

今天(通常)是真实的,但我不会假设未来的内核。没有具体说明,这只是当前的实施。内核人员可能想要改进它。 – 2012-02-28 17:19:35

+0

我会避免做出这样或那样的假设。例如,在非常大的映射之前添加少量的随机填充(未映射的页面)可能是安全/合理的(因为百分比开销/碎片必然非常小)。 – 2012-02-28 17:52:48