關(guān)于GCC的SSP棧溢出保護(hù)功能

本文摘自:?如何在實(shí)時(shí)操作系統(tǒng)(RTOS)中使用GCC的棧溢出保護(hù)(SSP)功能https://cloud.tencent.com/developer/article/1578337
而上文又是對(duì)?Using GCC's Stack Smashing Protector on microcontrollers(https://antoinealb.net/programming/2016/06/01/stack-smashing-protector-on-microcontrollers.html)?一文的翻譯
GCC編譯器提供了棧溢出保護(hù)功能(Stack Smashing Protection, 簡(jiǎn)稱SSP)。
要理解SSP首先要知道什么是棧溢出。
1. 什么是棧溢出
C語(yǔ)言中, 需要開發(fā)人員自己管理內(nèi)存, 不可避免的會(huì)引入一系列內(nèi)存相關(guān)的BUG, 比如: 內(nèi)存重復(fù)釋放、野指針、棧溢出等。這些問題通常都比較難定位, 因?yàn)槌鰡栴}的地方一般都不是案發(fā)現(xiàn)場(chǎng)(比如A處發(fā)生內(nèi)存越界寫操作, 可能在B處程序才異常)。
引用維基百科的說(shuō)法:?緩沖區(qū)溢出是指往內(nèi)存中寫數(shù)據(jù)時(shí), 越過了對(duì)應(yīng)的內(nèi)存邊界, 寫到了相鄰的內(nèi)存中。
如果發(fā)生溢出的緩沖區(qū)位于??臻g, 這就是棧溢出, 也就是說(shuō)棧溢出是緩沖區(qū)溢出的一種情況。
黑客可以利用棧溢出修改函數(shù)的返回地址, 從而改變程序的執(zhí)行邏輯。如果你的產(chǎn)品具有聯(lián)網(wǎng)功能, 就特別需要注意這一點(diǎn), 以免被攻擊。
以下面的代碼為例:
如果用戶提供的信息長(zhǎng)度超過16字節(jié), 將會(huì)導(dǎo)致Buffer發(fā)生緩沖區(qū)溢出, 多出來(lái)的數(shù)據(jù)將會(huì)被寫到Buffer緊鄰的內(nèi)存區(qū)域。如果棧幀中函數(shù)的返回地址被修改, 將會(huì)導(dǎo)致不可預(yù)見的異常。
2. GCC棧溢出保護(hù)的工作原理
GCC棧溢出保護(hù)(SSP)是在函數(shù)中插入一個(gè)額外的變量(stack canary), 該變量位于函數(shù)返回地址所在內(nèi)存的后面, 函數(shù)進(jìn)入的時(shí)候該變量被賦為特定的值, 函數(shù)返回前判斷該變量的值有沒有改變。如果變化了, 說(shuō)明出現(xiàn)了棧溢出, 這時(shí)候返回地址可能已經(jīng)被修改了。
下圖結(jié)合第一部分的代碼片段展示SSP的工作原理:
圖1是正常的調(diào)用不會(huì)產(chǎn)生任何異常;
圖2寫入了20個(gè)字節(jié), 導(dǎo)致Buffer發(fā)生緩沖區(qū)溢出, 并把返回地址覆蓋了, 這會(huì)導(dǎo)致程序產(chǎn)生非預(yù)期的行為, 但是程序并不知道發(fā)生了棧溢出;
圖3開啟了SSP, 函數(shù)返回的時(shí)候發(fā)現(xiàn)canary被修改, 檢測(cè)到棧溢出。

當(dāng)然, SSP并不能檢測(cè)所有的棧溢出, 但有勝于無(wú)。不過, SSP會(huì)增加運(yùn)行期消耗, 表現(xiàn)為使用的棧內(nèi)存增加, CPU執(zhí)行的指令增多??梢钥紤]在debug版本中開啟該功能, release版本中關(guān)閉該功能。