2011-05-14 84 views
8

我正在使用Debian擠壓並注意到內存始終爲零。這是在Linux發行版中的新功能嗎?前一段時間,我相信我可以使用puts()並輸出垃圾。內核零內存?

我多次運行這個測試程序,但評論結果總是相同的。 (我在sysctl.conf的randomize_va_space = 2,所以我知道,內存在不同的地點是在每次運行使用。)


char *a = malloc(50000000); 
a[49999999] = '\0'; 
puts(a); // it outputs nothing since all are zeroes 
printf("%p\n", a); 
if(a[5000] == '\0') // this condition is always true 
{ 
    puts("It is a nul char."); 
}

是否有可能使系統不爲零的內存?這個Debian擠壓安裝有什麼選擇可以激活這個始終爲零的內存?

回答

1

您的代碼不會測試所有內存是否歸零 - 它會測試兩個特定字節是否爲零 - a [0]和a [5000]。另外,malloc()與內核無關 - 它是一個C庫函數,不是系統調用。它的實現者零記憶是不太可能的 - 你所看到的只是你特定配置的隨機怪癖。

7

從我在Linux Kernel Development中讀到的內容來看,內核做零頁面是因爲它可能包含用戶程序可以解釋的內核數據並以某種方式訪問​​系統。

malloc向內核請求更多頁面,所以內核負責你正在接收的內存。

+0

根據這個WP頁面上的brk/sbrk函數:http://en.wikipedia.org/wiki/Sbrk你是對的。但是這對於內核來說似乎是一件非常浪費的事情。 – 2011-05-14 21:29:57

+2

爲什麼?這對於一個程序來說似乎是一件聰明的事情。如果你有非常愚蠢的程序來保存未加密的愚蠢數據,然後在沒有免費()的情況下死掉,你可能會編寫一個程序來利用它。我很肯定你可以在編譯內核時禁用它。 – 2011-05-14 23:12:11

+0

「禁用它」?絕對沒有辦法通過普通選項向內核泄露數據給用戶空間。你不得不故意破壞它來做到這一點。由於新頁面是COW引用零頁面的事實,因此不存在會泄漏的「缺省情況」。 – 2011-05-15 03:43:09

3

你第一次malloc一個塊內存有一個公平的機會它將爲零,因爲系統調用(sbrk,mmap)分配的內存由內核歸零。但是,如果你再次釋放並再次使用malloc,則內存將被回收並可能不包含零。

1

在大多數進程之間有隔離的操作系統上,您會發現內存已被調整。原因在於不能允許進程偷看另一個進程釋放的內存,因此內存頁必須在某個進程釋放的時間與其他進程釋放的時間之間被擦除。在實踐中,擦除意味着歸零,並且內存在進程分配時通常爲零。

當你在你的玩具程序中調用malloc時,內存還沒有用於其他任何事情。所以它在內核中仍然是新鮮的,充滿了零。如果你嘗試了一個已經分配並釋放了很多堆塊的真正程序,你會發現你的進程已經使用了的內存仍然包含你(或者內存管理系統)可能存在的任何垃圾。

16

在任何現代操作系統上,新獲得的內存的唯一方式將包含非零值,如果以前由程序釋放的內存被malloc重用。當從操作系統(內核)獲得新內存時,它最初是純虛擬。它沒有物質存在;而是將其映射爲充滿0字節的單個共享內存頁的寫時拷貝映射。當您第一次嘗試寫入內核時,內核將捕獲寫入,分配一個新的物理內存頁面,將原始頁面的內容(本例中全部爲0字節)複製到新頁面,然後恢復你的程序。如果內核知道新分配的物理內存已經被填滿,它甚至可以優化複製步驟。

此過程既必要又高效。這是必要的,因爲將可能包含來自內核或其他用戶進程的私有數據的內存移交給您的進程將是嚴重的安全漏洞。這是有效的,因爲在分配時不執行歸零操作; 「零填充」頁面只是引用共享的零頁面。

+0

Windows中有一個線程,其任務是將未使用的物理頁面清零,以提供可安全映射到用戶空間的新頁面池。 (通過比較,允許內核爲其自己使用分配未定位頁面)。 – Neil 2011-05-14 22:06:43

+0

然而,內核開發者仍然必須確保其「未定界」頁面的內存中的數據不會泄漏到任何用戶模式進程中。 此外,考慮到內存在後臺調​​零,除非有明顯的內存流失,否則對系統的影響最小。但是,無論是否進行調零,通過記憶攪動都可能是性能問題。 – Brian 2011-05-14 22:43:17

1

如已經說明的,關鍵的區別是第一次分配分配。如果你嘗試:

char *a, tst; 
do { 
    a = malloc(50000000); 
    a[49999999] = '\0'; 
    printf("%50s\n%p", a, a); // it outputs nothing 1st, but bbbb.... 2nd 
    tst = a[5000] 
    memset(a, 'b', 50000000); 
    free(a); 
} while (tst == '\0'); 

它會打印你兩行(最有可能,至少如果指針是相同的)。

關鍵是由malloc()返回的內存塊有未定義的內容。它可能也可能不是零,並且取決於程序過去如何完成內存分配(或者使用了什麼內存調試工具)。

如果要保證的內容,則需要calloc()或分配後進行顯式初始化。

在另一方面該系統的完整性/數據分離保證意味着由系統要求的任何初始地址空間 - 無論是通過sbrk()mmap(MAP_ANON) - 必須是零初始化,作爲此類的任何其它內容將包括一個安全漏洞。