存越界訪問:原理、檢測(cè)與防御實(shí)戰(zhàn)指南)
1. 項(xiàng)目概述理解內(nèi)存的“圍墻”與“越界”在Linux系統(tǒng)開發(fā)與運(yùn)維的日常里內(nèi)存管理是核心中的核心。我們編寫的程序無論是C/C這類貼近硬件的語言還是Python、Go等高級(jí)語言最終都要在內(nèi)存這個(gè)舞臺(tái)上運(yùn)行。你可以把內(nèi)存想象成一個(gè)巨大、有序的公寓樓每個(gè)程序入住時(shí)操作系統(tǒng)Linux內(nèi)核會(huì)為它分配一個(gè)或多個(gè)“房間”內(nèi)存段并明確告知其房間號(hào)地址和大小邊界。程序必須嚴(yán)格遵守這個(gè)邊界在自己的房間里活動(dòng)。而“越界訪問”就是這個(gè)程序不守規(guī)矩試圖去開隔壁房間的門甚至跑到樓道、地下室等不屬于它的區(qū)域去讀寫數(shù)據(jù)。這聽起來似乎只是程序員的粗心但實(shí)際上它引發(fā)的后果遠(yuǎn)比想象中嚴(yán)重。輕則導(dǎo)致程序行為詭異、數(shù)據(jù)損壞你可能會(huì)遇到一些“玄學(xué)”bug比如某個(gè)變量毫無征兆地變成了奇怪的值或者程序在某個(gè)看似無關(guān)的操作后崩潰。重則它可能被惡意利用成為系統(tǒng)安全的致命漏洞。攻擊者通過精心構(gòu)造的輸入誘使程序發(fā)生越界寫操作從而覆蓋關(guān)鍵數(shù)據(jù)、劫持程序執(zhí)行流程甚至獲取系統(tǒng)控制權(quán)。因此理解、預(yù)防和排查越界訪問是每一位與Linux系統(tǒng)打交道的開發(fā)者、運(yùn)維工程師乃至安全研究員必須掌握的內(nèi)功。本文將從一個(gè)資深系統(tǒng)工程師的視角深入拆解Linux環(huán)境下越界訪問的方方面面。我們不會(huì)停留在概念層面而是會(huì)深入到虛擬內(nèi)存機(jī)制、編譯器行為、調(diào)試工具使用以及實(shí)際案例中告訴你它究竟如何發(fā)生、如何發(fā)現(xiàn)、如何修復(fù)以及最重要的——如何從編碼習(xí)慣和系統(tǒng)設(shè)計(jì)層面避免它。無論你是正在學(xué)習(xí)系統(tǒng)編程的新手還是被偶發(fā)性崩潰困擾的老手這篇文章都將提供一套完整的實(shí)戰(zhàn)指南。2. 內(nèi)存越界的核心原理與分類拆解要有效防治越界首先得明白它的“作案手法”。在Linux的虛擬內(nèi)存模型下每個(gè)進(jìn)程都擁有獨(dú)立的、從0開始的連續(xù)虛擬地址空間。這個(gè)空間被劃分為幾個(gè)標(biāo)準(zhǔn)區(qū)域代碼段.text、數(shù)據(jù)段.data, .bss、堆heap和棧stack。越界訪問可以發(fā)生在任何這些區(qū)域。2.1 棧溢出最常見的“鄰里糾紛”棧是用于存儲(chǔ)函數(shù)調(diào)用上下文返回地址、參數(shù)、局部變量的內(nèi)存區(qū)域它的增長(zhǎng)方向是自頂向下從高地址向低地址。棧溢出通常發(fā)生在對(duì)棧上的數(shù)組或緩沖區(qū)進(jìn)行寫入時(shí)寫入了超出其分配空間的數(shù)據(jù)覆蓋了相鄰的數(shù)據(jù)。典型場(chǎng)景void vulnerable_function(char *input) { char buffer[64]; // 在棧上分配64字節(jié)緩沖區(qū) strcpy(buffer, input); // 如果input長(zhǎng)度超過63字節(jié)加上結(jié)尾的\0就會(huì)發(fā)生溢出 }當(dāng)input長(zhǎng)度超過63字節(jié)時(shí)strcpy會(huì)持續(xù)寫入覆蓋掉buffer之后的內(nèi)容。這些內(nèi)容可能包括其他局部變量導(dǎo)致它們的值被意外修改。保存的幀指針EBP/RBP破壞函數(shù)調(diào)用鏈的恢復(fù)。函數(shù)的返回地址EIP/RIP這是最危險(xiǎn)的情況。攻擊者可以精心構(gòu)造input使其在覆蓋返回地址時(shí)填入一個(gè)指向惡意代碼的地址從而完全控制程序流。注意現(xiàn)代Linux發(fā)行版默認(rèn)啟用了棧保護(hù)機(jī)制如Stack Canary、NX位使得直接利用棧溢出執(zhí)行代碼變得困難但它仍然會(huì)導(dǎo)致程序崩潰段錯(cuò)誤并且在一些特定條件下或配合其他漏洞仍可能被利用。2.2 堆溢出管理混亂的“公共區(qū)域”堆是用于動(dòng)態(tài)分配內(nèi)存的區(qū)域通過malloc、calloc、new等。堆管理器如glibc的ptmalloc負(fù)責(zé)分配和回收內(nèi)存塊。堆溢出發(fā)生在向動(dòng)態(tài)分配的緩沖區(qū)寫入超過其大小的數(shù)據(jù)時(shí)。原理深入堆管理器為了管理內(nèi)存會(huì)在分配給用戶的內(nèi)存塊前后放入一些管理數(shù)據(jù)元數(shù)據(jù)例如塊大小、前后塊指針等。一個(gè)典型的堆溢出可能覆蓋相鄰的用戶數(shù)據(jù)導(dǎo)致另一個(gè)無關(guān)變量被修改。覆蓋堆管理元數(shù)據(jù)這是更危險(xiǎn)的。攻擊者可以通過溢出精心修改這些元數(shù)據(jù)誘騙堆管理器在后續(xù)的malloc或free操作中向任意地址比如GOT表寫入數(shù)據(jù)或返回一個(gè)受控的指針從而實(shí)現(xiàn)“任意地址寫”或“任意地址讀”最終可能達(dá)成代碼執(zhí)行。char *a (char*)malloc(64); char *b (char*)malloc(64); // 假設(shè)a和b在內(nèi)存中相鄰 strcpy(a, very_long_input); // 溢出a可能覆蓋b的內(nèi)容或b塊頭的元數(shù)據(jù) free(b); // 如果b的元數(shù)據(jù)已被破壞執(zhí)行free時(shí)可能導(dǎo)致堆管理器內(nèi)部狀態(tài)錯(cuò)亂進(jìn)而崩潰或更糟。2.3 全局/靜態(tài)數(shù)據(jù)區(qū)越界發(fā)生在全局變量.data段或靜態(tài)變量.bss段的數(shù)組或緩沖區(qū)上。由于這些區(qū)域在程序生命周期內(nèi)一直存在且位置相對(duì)固定此類越界可能會(huì)持續(xù)破壞程序狀態(tài)但通常不如棧和堆溢出那樣容易直接導(dǎo)向流程劫持。2.4 讀越界與寫越界讀越界讀取了分配區(qū)域之外的內(nèi)存。這可能導(dǎo)致信息泄露Leak例如讀取到棧上的殘留數(shù)據(jù)、堆上的其他數(shù)據(jù)甚至可能讀到一些敏感信息如密鑰、地址信息。雖然不直接導(dǎo)致崩潰或執(zhí)行代碼但嚴(yán)重危害安全性。寫越界向分配區(qū)域之外的內(nèi)存寫入數(shù)據(jù)。這是我們主要討論的、危害更大的類型因?yàn)樗鼤?huì)主動(dòng)破壞數(shù)據(jù)或代碼邏輯。3. 實(shí)戰(zhàn)探測(cè)如何發(fā)現(xiàn)越界訪問這只“幽靈”越界訪問的bug往往具有隱蔽性和隨機(jī)性像幽靈一樣時(shí)隱時(shí)現(xiàn)。依賴“運(yùn)行-崩潰-打印日志”的傳統(tǒng)方式效率極低。下面介紹幾種在Linux下高效的探測(cè)手段。3.1 編譯器內(nèi)置工具第一道防線現(xiàn)代GCC/Clang編譯器提供了強(qiáng)大的編譯時(shí)和運(yùn)行時(shí)檢查選項(xiàng)應(yīng)在開發(fā)階段全程開啟。編譯警告-Wall -Wextra這是最基本的。許多簡(jiǎn)單的越界嫌疑如strcpy會(huì)觸發(fā)警告。務(wù)必以最高警告級(jí)別-Wall -Wextra -Werror將警告視為錯(cuò)誤編譯代碼。AddressSanitizer (ASan)這是目前最強(qiáng)大、最常用的內(nèi)存錯(cuò)誤檢測(cè)工具。它在編譯時(shí)插樁在運(yùn)行時(shí)監(jiān)控內(nèi)存操作。gcc -fsanitizeaddress -g -o test_program test.c ./test_program當(dāng)發(fā)生越界訪問時(shí)ASan會(huì)立即報(bào)告錯(cuò)誤并給出極其詳細(xì)的診斷信息包括出錯(cuò)位置、堆棧、內(nèi)存映射、以及錯(cuò)誤類型heap-buffer-overflow, stack-buffer-overflow, global-buffer-overflow等。它對(duì)性能有一定影響約2倍但用于調(diào)試是完全可接受的。UndefinedBehaviorSanitizer (UBSan)檢測(cè)未定義行為某些導(dǎo)致越界的算術(shù)溢出如數(shù)組索引計(jì)算溢出會(huì)被它捕獲。gcc -fsanitizeundefined -g -o test_program test.c實(shí)操心得在CI/CD流水線中至少應(yīng)包含一個(gè)使用ASan編譯和運(yùn)行測(cè)試套件的任務(wù)。這能將很多內(nèi)存問題扼殺在合并之前。3.2 專業(yè)調(diào)試與內(nèi)存分析工具當(dāng)問題在特定環(huán)境復(fù)現(xiàn)或需要更深入分析時(shí)需要更專業(yè)的工具。Valgrind 及其 Memcheck 工具一個(gè)動(dòng)態(tài)二進(jìn)制插樁框架。Memcheck是它的默認(rèn)工具可以檢測(cè)未初始化的內(nèi)存使用、內(nèi)存泄漏、以及越界訪問特別是讀越界和釋放后訪問。valgrind --toolmemcheck --leak-checkfull ./your_programValgrind運(yùn)行速度很慢可能慢20-30倍但無需重新編譯程序適合排查已部署二進(jìn)制文件的問題。它對(duì)棧上數(shù)組的越界檢測(cè)能力較弱但對(duì)堆內(nèi)存的檢測(cè)非常強(qiáng)大。GDB 調(diào)試器當(dāng)程序因越界導(dǎo)致段錯(cuò)誤SIGSEGV崩潰時(shí)GDB是定位問題的利器。使用gdb ./program core加載核心轉(zhuǎn)儲(chǔ)文件。使用btbacktrace查看崩潰時(shí)的調(diào)用棧。使用info registers查看寄存器值特別是rip指令指針和rsp棧指針。使用x命令檢查崩潰地址附近的內(nèi)存內(nèi)容。高級(jí)技巧可以設(shè)置內(nèi)存觀察點(diǎn)watch來監(jiān)控特定內(nèi)存地址的讀寫這對(duì)于追蹤某個(gè)神秘變量被誰修改非常有效。3.3 系統(tǒng)級(jí)監(jiān)控與日志核心轉(zhuǎn)儲(chǔ)Core Dump確保系統(tǒng)允許生成核心轉(zhuǎn)儲(chǔ)ulimit -c unlimited。崩潰時(shí)生成的核心文件包含了進(jìn)程死亡瞬間的完整內(nèi)存映像是事后分析的寶貴資料。審計(jì)日志Linux內(nèi)核的審計(jì)子系統(tǒng)可以記錄特定的系統(tǒng)調(diào)用。你可以配置規(guī)則來審計(jì)所有SIGSEGV段錯(cuò)誤信號(hào)的發(fā)送這有助于在分布式系統(tǒng)中追蹤是哪個(gè)進(jìn)程、在何時(shí)發(fā)生了崩潰。4. 防御之道從編碼到架構(gòu)的系統(tǒng)性規(guī)避檢測(cè)是事后補(bǔ)救防御才是根本。以下是從編碼習(xí)慣到系統(tǒng)設(shè)計(jì)的層層防御策略。4.1 安全的編碼實(shí)踐與API選擇這是最有效、成本最低的一環(huán)。摒棄不安全的字符串函數(shù)永遠(yuǎn)不要使用strcpy,strcat,gets,sprintf。使用它們的安全版本strncpy-strlcpy(非標(biāo)準(zhǔn)但更安全) 或 手動(dòng)控制strncat-strlcat或 手動(dòng)控制gets-fgetssprintf-snprintf注意strncpy并不保證結(jié)果字符串以\0結(jié)尾使用不當(dāng)仍會(huì)出問題。snprintf是更可靠的選擇。進(jìn)行邊界檢查在任何涉及數(shù)組索引或指針運(yùn)算的地方顯式檢查是否越界。int write_to_buffer(char *buf, size_t buf_size, const char *data, size_t data_len) { if (data_len buf_size) { // 注意是 因?yàn)橐A(yù)留結(jié)尾的\0 return -1; // 錯(cuò)誤處理 } memcpy(buf, data, data_len); buf[data_len] \0; return 0; }使用更安全的數(shù)據(jù)結(jié)構(gòu)和庫(kù)C優(yōu)先使用std::vector、std::array、std::string它們自動(dòng)管理邊界。C可以考慮使用libsafe等庫(kù)或自行封裝帶長(zhǎng)度檢查的緩沖區(qū)操作函數(shù)。謹(jǐn)慎處理用戶輸入所有來自外部的輸入網(wǎng)絡(luò)、文件、命令行都應(yīng)視為不可信的必須經(jīng)過嚴(yán)格的驗(yàn)證和凈化Validation and Sanitization才能用于內(nèi)存操作。4.2 利用編譯器和操作系統(tǒng)提供的保護(hù)機(jī)制現(xiàn)代Linux系統(tǒng)和編譯器提供了多層“鎧甲”應(yīng)充分利用。棧保護(hù)Stack Canary編譯器選項(xiàng)-fstack-protector或-fstack-protector-strong。它在函數(shù)棧幀的返回地址前插入一個(gè)隨機(jī)值金絲雀函數(shù)返回前檢查該值是否被改變。若改變則立即終止程序。這是對(duì)抗棧溢出的標(biāo)準(zhǔn)配置。數(shù)據(jù)執(zhí)行保護(hù)NX/DEP標(biāo)記內(nèi)存頁(yè)為不可執(zhí)行。這樣即使攻擊者將代碼注入到?;蚨阎幸矡o法執(zhí)行?,F(xiàn)代CPU和Linux內(nèi)核默認(rèn)支持。地址空間布局隨機(jī)化ASLR隨機(jī)化棧、堆、庫(kù)的加載地址增加攻擊者預(yù)測(cè)目標(biāo)地址的難度。通過/proc/sys/kernel/randomize_va_space控制。位置無關(guān)可執(zhí)行文件PIE編譯時(shí)使用-fPIE -pie使程序主體代碼的地址也隨機(jī)化與ASLR配合提供更強(qiáng)的保護(hù)。強(qiáng)化工具鏈在編譯時(shí)指定-D_FORTIFY_SOURCE2它會(huì)在編譯時(shí)對(duì)一些標(biāo)準(zhǔn)庫(kù)函數(shù)調(diào)用進(jìn)行更強(qiáng)的邊界檢查。一個(gè)相對(duì)安全的編譯命令示例gcc -Wall -Wextra -Werror -O2 -fstack-protector-strong -D_FORTIFY_SOURCE2 -fPIE -pie -o program program.c4.3 架構(gòu)與設(shè)計(jì)層面的考量對(duì)于大型或安全性要求極高的系統(tǒng)需要在設(shè)計(jì)時(shí)就考慮內(nèi)存安全。內(nèi)存安全語言在合適的新模塊或項(xiàng)目中考慮使用Rust、Go等內(nèi)存安全的語言。它們通過所有權(quán)、借用檢查器Rust或垃圾回收與邊界檢查Go在編譯時(shí)或運(yùn)行時(shí)杜絕了絕大部分內(nèi)存安全問題。沙箱與隔離將不可信的組件如解析復(fù)雜格式的庫(kù)放入獨(dú)立的進(jìn)程或容器中運(yùn)行通過進(jìn)程間通信IPC與之交互。即使該組件被攻破其破壞也被限制在沙箱內(nèi)。形式化驗(yàn)證與靜態(tài)分析對(duì)于核心安全模塊可以使用像Frama-C這樣的工具進(jìn)行形式化驗(yàn)證或使用Coverity、Clang Static Analyzer等高級(jí)靜態(tài)分析工具進(jìn)行深度代碼掃描發(fā)現(xiàn)潛在缺陷。5. 深度排查當(dāng)越界訪問導(dǎo)致詭異崩潰時(shí)假設(shè)你面對(duì)一個(gè)線上服務(wù)它偶爾會(huì)崩潰生成一個(gè)核心轉(zhuǎn)儲(chǔ)文件日志里只有一句“Segmentation fault”。你該如何抽絲剝繭5.1 第一步初步分析核心轉(zhuǎn)儲(chǔ)# 加載核心文件和調(diào)試符號(hào) gdb /path/to/your/program /path/to/core.file # 查看崩潰時(shí)的線程和調(diào)用棧 (gdb) bt full # 查看崩潰的指令和寄存器 (gdb) info registers (gdb) x/i $rip通過bt你可能會(huì)發(fā)現(xiàn)崩潰發(fā)生在libc的free()或malloc()函數(shù)中或者某個(gè)字符串函數(shù)里。這通常意味著堆元數(shù)據(jù)被破壞而破壞可能發(fā)生在更早的時(shí)候。5.2 第二步判斷破壞范圍與時(shí)間如果GDB顯示堆損壞問題可能比較復(fù)雜。此時(shí)可以檢查是否有并發(fā)問題如果程序是多線程的并且在沒有同步的情況下操作了同一個(gè)堆緩沖區(qū)那么這就是一個(gè)典型的“數(shù)據(jù)競(jìng)爭(zhēng)”導(dǎo)致的堆損壞。檢查代碼中對(duì)全局或共享緩沖區(qū)的訪問是否加鎖。使用MALLOC_CHECK_環(huán)境變量Glibc提供了一個(gè)環(huán)境變量MALLOC_CHECK_。設(shè)置MALLOC_CHECK_1glibc會(huì)在檢測(cè)到堆錯(cuò)誤時(shí)打印診斷信息設(shè)置MALLOC_CHECK_2它會(huì)立即調(diào)用abort()終止程序讓你能在破壞發(fā)生的第一時(shí)間獲得核心轉(zhuǎn)儲(chǔ)而不是等到后續(xù)某個(gè)free操作時(shí)才崩潰。MALLOC_CHECK_2 ./your_program5.3 第三步使用高級(jí)工具進(jìn)行現(xiàn)場(chǎng)復(fù)現(xiàn)與追蹤如果問題難以穩(wěn)定復(fù)現(xiàn)可以考慮使用ASan記錄日志即使ASan使程序變慢也可以嘗試在測(cè)試環(huán)境長(zhǎng)期運(yùn)行帶ASan版本的程序等待問題復(fù)現(xiàn)。ASan的報(bào)告能精準(zhǔn)定位第一次越界發(fā)生的地點(diǎn)。使用Valgrind的SGCheck工具--toolexp-sgcheck可以檢測(cè)棧和全局?jǐn)?shù)組的越界作為Memcheck的補(bǔ)充。硬件斷點(diǎn)與GDB腳本如果懷疑某個(gè)特定變量被篡改可以在GDB中對(duì)其地址設(shè)置觀察點(diǎn)watch并編寫GDB腳本自動(dòng)記錄每次寫入的調(diào)用棧。5.4 一個(gè)典型排查案例堆溢出破壞元數(shù)據(jù)現(xiàn)象服務(wù)隨機(jī)崩潰bt顯示在free()中。排查使用MALLOC_CHECK_2運(yùn)行獲得一個(gè)更早的核心轉(zhuǎn)儲(chǔ)。在新核心文件中bt顯示崩潰發(fā)生在strcpy到一個(gè)動(dòng)態(tài)分配的緩沖區(qū)之后。檢查該緩沖區(qū)的分配大小和strcpy的源字符串長(zhǎng)度發(fā)現(xiàn)源字符串長(zhǎng)度遠(yuǎn)超分配大小。根源代碼中使用了strcpy(dest, src)而src是用戶可控的網(wǎng)絡(luò)數(shù)據(jù)。沒有進(jìn)行長(zhǎng)度檢查。修復(fù)將strcpy改為snprintf(dest, dest_size, %s, src)或使用帶長(zhǎng)度檢查的封裝函數(shù)。6. 進(jìn)階話題與其他漏洞的關(guān)聯(lián)與利用初探從安全研究的角度理解越界訪問如何被利用是做好防御的前提。這里僅做原理性簡(jiǎn)述旨在強(qiáng)調(diào)其危害性。6.1 從越界讀到信息泄露如果存在一個(gè)越界讀漏洞攻擊者可以像“窺探”內(nèi)存一樣讀取進(jìn)程地址空間中的其他數(shù)據(jù)。這可能包括棧上的返回地址幫助繞過ASLR。堆上的指針揭示堆布局。.got.plt表中的函數(shù)地址同樣是繞過ASLR的關(guān)鍵信息。程序中的敏感數(shù)據(jù)如加密密鑰、用戶隱私。這些泄露的信息本身可能構(gòu)成危害也能為后續(xù)更復(fù)雜的攻擊如ROP鏈構(gòu)造鋪平道路。6.2 從越界寫到代碼執(zhí)行這是最嚴(yán)重的后果。通過越界寫攻擊者可以覆蓋函數(shù)指針程序中的函數(shù)指針如回調(diào)函數(shù)、C虛表指針被覆蓋后可以指向攻擊者控制的數(shù)據(jù)如shellcode或gadget地址。覆蓋返回地址經(jīng)典的棧溢出利用方式。覆蓋GOT表全局偏移表GOT存儲(chǔ)著動(dòng)態(tài)鏈接函數(shù)的實(shí)際地址。覆蓋GOT表中某個(gè)函數(shù)如system的條目可以在程序下次調(diào)用該函數(shù)時(shí)跳轉(zhuǎn)到攻擊者指定的地址?,F(xiàn)代防護(hù)機(jī)制ASLR, NX, Stack Canary, RELRO使得這些利用變得極具挑戰(zhàn)性但并非不可能。攻擊者往往會(huì)結(jié)合信息泄露漏洞先獲取地址和復(fù)雜的利用技術(shù)如ROP來繞過這些防護(hù)。6.3 對(duì)系統(tǒng)穩(wěn)定性的影響即使不考慮惡意利用越界訪問對(duì)系統(tǒng)穩(wěn)定性也是災(zāi)難性的。它可能破壞其他進(jìn)程的數(shù)據(jù)雖然由于虛擬內(nèi)存隔離直接破壞其他進(jìn)程較難但可通過共享內(nèi)存發(fā)生。導(dǎo)致內(nèi)存管理子系統(tǒng)如glibc的堆管理器內(nèi)部狀態(tài)不一致引發(fā)不可預(yù)測(cè)的行為。使系統(tǒng)服務(wù)崩潰導(dǎo)致拒絕服務(wù)DoS。7. 工具鏈與最佳實(shí)踐總結(jié)工欲善其事必先利其器。下面我將日常工作中形成的工具鏈和習(xí)慣整理成表供你參考。階段工具/實(shí)踐目的備注開發(fā)中-Wall -Wextra -Werror捕獲簡(jiǎn)單編碼錯(cuò)誤必須開啟-fstack-protector-strong棧溢出保護(hù)默認(rèn)開啟-D_FORTIFY_SOURCE2強(qiáng)化標(biāo)準(zhǔn)庫(kù)函數(shù)生產(chǎn)環(huán)境建議-fPIE -pie配合ASLR安全要求高時(shí)開啟調(diào)試/測(cè)試-fsanitizeaddress(ASan)檢測(cè)內(nèi)存錯(cuò)誤功能測(cè)試必備-fsanitizeundefined(UBSan)檢測(cè)未定義行為輔助使用Valgrind Memcheck檢測(cè)內(nèi)存錯(cuò)誤、泄漏無需重編譯深度測(cè)試GDB交互式調(diào)試、分析核心轉(zhuǎn)儲(chǔ)問題定位終極工具CI/CDASan/UBSan測(cè)試套件自動(dòng)化內(nèi)存問題檢測(cè)流水線中必須包含靜態(tài)分析工具(如Clang SA)代碼質(zhì)量掃描定期運(yùn)行線上防護(hù)ASLR(randomize_va_space2)增加利用難度系統(tǒng)默認(rèn)NX(DEP)阻止數(shù)據(jù)執(zhí)行CPU/系統(tǒng)默認(rèn)支持核心轉(zhuǎn)儲(chǔ)保存崩潰現(xiàn)場(chǎng)配置合理的保存策略最后我想分享一個(gè)最深刻的體會(huì)對(duì)待內(nèi)存要像對(duì)待火藥一樣謹(jǐn)慎。每一次malloc都要想好free每一次數(shù)組訪問都要在心底默念邊界每一次處理外部數(shù)據(jù)都要假設(shè)它充滿惡意。越界訪問這類問題幾乎總是源于一時(shí)的僥幸和疏忽。建立起一套從編碼習(xí)慣、工具檢查到架構(gòu)防御的完整體系并將其固化為團(tuán)隊(duì)規(guī)范是根除這類“幽靈”bug的唯一途徑。在Linux這個(gè)世界里對(duì)內(nèi)存的敬畏是通往穩(wěn)定與安全的基石。