Linux核心記憶體保護機制:aslr和canary
ASLR
ASLR技術,全稱為Address space layout randomization(地址空間佈局隨機化),是現代通用作業系統基本都會配備的一個功能,其確保了每次例項化程序時記憶體排布都是不同的。
對於某些記憶體段,會附加隨機的offset來防止緩衝區攻擊等,這是OS層面的保護,當然也可以相容硬體層面使用ECC bit進行合法性檢測的冗餘保護。
更確切的說,在Linux系統下的程序模型中,aslr對於記憶體排布的影響如下:
- 不變:程式碼段/BSS/全域性資料區等
- 改變:載入的依賴庫的程式碼位置(手動連結的,最典型的是glibc,e.g. 比如使用printf的時候重放會出現連結空間地址段錯誤,若停用aslr則可以進行攻擊),棧空間,堆空間等(後兩者視aslr的不同層級,有可能不會附加,取決於核心版本)
程序地址空間排布(來自程式碼隨想錄,僅供參考):
在GDB環境下執行程式,aslr是預設關閉的,這也便於我們進行程式的除錯。
這裡舉出來一個典型的實用案例:
我在工作的實際需求中需要建立一個虛擬化的沙盒,底層基座依賴了一個uni-kernel的bsd系統,出於sandbox的snapshot遷移重放需求,需要手動關閉aslr機制,並附加硬體層面的記憶體保護。
開啟/關閉aslr執行以下程式碼,開啟為1,關閉為0:
sysctl kern.elf64.aslr.stack=0
sysctl kern.elf64.aslr.pie_enable=0
sysctl kern.elf64.aslr.enable=0
sysctl kern.elf64c.aslr.stack=0
sysctl kern.elf64c.aslr.pie_enable=0
sysctl kern.elf64c.aslr.enable=0
sysctl -a | grep aslr
如果使用gcc編譯器的時候,可以附加-fPIE
的編譯選項,以支援aslr機制。
canary
我們的棧中通常有一個magic number,用來檢測該塊記憶體空間是否被其他意外修改。它有一個好聽的名字:canary,金絲雀,美麗而又脆弱。
它通常被部署在棧頂返回地址附近的某個位置,確保該處空間沒有被外部緩衝區溢位修改,雖然只是一個簡單的機制,但是可以防止很多比較簡單的攻擊或者非惡意失誤,是記憶體保護的第一道防線。
通常在函式被呼叫時生成,且該段對於使用者態來說是嚴格不可讀的,所以只能用fork/提權/劫持sys函式等暴力破拆的方式探測處理。
這個思想不僅限於核心場景,在通用需求下做資料校驗的時候也可以使用,或者需求可靠的TCB場景時也可用。這種情況下就是在user space中進行自定義規則的校驗了。
在gcc/clang中可以使用-fno-stack-protector
編譯選項來停用canary,但如果你不明確知道自己在幹什麼,不要這麼做!