美團二面:為什么mmap共享內存比malloc危險?
今天來聊個面試題,為什么mmap共享內存比malloc更危險,這是一個比較有區分度的題目。
在系統編程中,內存管理是程序員必須面對的核心問題之一。
C/C++開發者常用的內存分配方式包括malloc(堆內存)和mmap(共享內存/文件映射)。
圖片
雖然兩者都能提供內存分配的能力,但從系統風險的角度來看,mmap共享內存比malloc更加危險,稍有不慎就可能引發嚴重的安全漏洞或穩定性問題。
mmap共享內存可能導致其它進程崩潰
mmap可以讓多個進程直接讀寫同一塊物理內存,這意味著一個進程的錯誤操作可能直接影響其他進程的數據,甚至導致崩潰。比如進程A的越界寫入可能導致進程B崩潰或讀取到損壞的數據。
一句話,共享內存破壞了進程間的內存隔離。
圖片
而如果使用malloc,這種越界寫入最多只會影響當前進程,不會跨進程傳播錯誤。因為malloc分配的內存僅在當前進程內有效,天然具備隔離性,其他進程無法直接訪問。
mmap的權限風險
mmap可以設置內存的讀寫/執行權限(如PROT_EXEC),如果錯誤配置可能被黑客利用進行代碼注入攻擊(如緩沖區溢出后執行惡意代碼)。
假設有一個網絡服務程序,使用 mmap 分配了一塊內存用于處理客戶端請求,并錯誤地賦予了可執行權限(PROT_EXEC):
void *mem_start = mmap(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
同時,程序將用戶輸入數據(如網絡數據包)復制到該內存區域,但未檢查輸入長度。
這樣攻擊者就可以構造一個超長數據包,其中包含惡意機器碼(如 shellcode)和精心設計的溢出數據,溢出數據覆蓋了程序的返回地址或函數指針,使其指向 mem_start 的起始地址。
當程序執行到該返回地址時,會跳轉到 mem_start 區域。
圖片
由于 mem_start 被錯誤配置為可執行(PROT_EXEC),因此操作系統不會阻止該區域的代碼執行。
攻擊者的 shellcode 被成功執行,可能實現提權、反彈 Shell 等惡意操作。
而使用malloc分配的堆內存則無此問題。
多線程與同步風險
使用mmap共享內存時,多進程或線程需通過信號量、鎖等機制同步訪問,否則導致數據競爭(Data Race)或臟讀,這顯然會影響所有共享這塊內存的進程。
圖片
malloc本身是線程安全的(通過全局鎖或線程本地緩存),但程序員需自行管理分配的內存區域的并發訪問。若未加鎖,仍可能導致競爭條件,但與mmap的共享內存相比,影響范圍限于當前進程內。