動態記憶體管理

堆積緩衝區溢位(heap buffer overflow)

你租了一個剛好能放 10 個箱子的櫃子,卻一直堆到第 12 個——最後兩個溢進你隔壁的櫃子,弄亂了鄰居存放的東西。堆積緩衝區溢位就是寫入(或讀取)超過你所配置區塊的尾端,於是你碰到了屬於另一筆配置、屬於配置器自己的記帳、或根本不是有效記憶體的地方。

精確地說:當你 malloc(n) 個位元組時,你唯一被允許碰的就是位移 0 到 n-1 的那些位元組。索引或用指標走到位移 n 或更後面——或走到區塊之前的負位移——就是越界存取與未定義行為。經典的觸發是差一錯誤:為一個長度 len 的字串配置空間,卻忘了字串結尾字元那一個額外位元組,於是寫入結尾的 0 就落在尾端後一個位元組。另一種是把超過區塊容量的資料複製進去,例如把使用者輸入讀進一個固定大小的堆積緩衝區卻不檢查長度。由於你區塊後面緊接的位元組常存放著下一塊的配置器中介資料,溢位往往破壞那份記帳,程式便在稍後、於 malloc 或 free 內部當機,離真正溢位的那一行很遠。

這是最古老、被利用最多的安全漏洞類別之一。藉由以受控方式溢位堆積緩衝區,攻擊者能覆寫相鄰物件——在最糟情況下包括函式指標或配置器中介資料——進而引導程式執行他們選定的程式碼。防禦是邊界紀律(永遠為資料加上任何結尾字元配置足夠的 sizeof,絕不寫入超過你所要求的大小)與工具:AddressSanitizer 會在配置周圍放置守衛區並回報確切的越界存取,Valgrind 也能抓到許多溢位。

char *s = malloc(5); /* 容納 5 個位元組:索引 0..4 */ strcpy(s, "hello"); /* 'h','e','l','l','o','\0' = 6 個位元組 -> 溢位! */ /* 正確:malloc(strlen("hello") + 1) 為字串結尾字元留出空間 */

一塊 5 位元組區塊裝不下 5 個字元的字串加上字串結尾字元;第六個位元組溢位。

當機常在稍後、於 malloc 或 free 內部發生,因為溢位破壞了下一塊的標頭——看得見的症狀離真正的錯誤很遠。

又称
out-of-bounds heap accessheap overrun堆積越界存取