2012-02-28 61 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