0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

一文解析AddressSanitizer算法及源碼

Linux閱碼場(chǎng) ? 來(lái)源:網(wǎng)絡(luò)整理 ? 作者:工程師陳翠 ? 2018-07-28 11:41 ? 次閱讀

AddressSanitizer簡(jiǎn)介

AddressSanitizer是Google用于檢測(cè)內(nèi)存各種buffer overflow(Heap buffer overflow, Stack buffer overflow, Global buffer overflow)的一個(gè)非常有用的工具。該工具是一個(gè)LLVM的Pass,現(xiàn)已集成至llvm中,要是用它可以通過(guò)-fsanitizer=address選項(xiàng)使用它。AddressSanitizer的源碼位于/lib/Transforms/Instrumentation/AddressSanitizer.cpp中,Runtime-library的源碼在llvm的另一個(gè)項(xiàng)目compiler-rt的/lib/asan文件夾中。

AddressSanitizer算法

具體的算法可以參考WIKI(https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm),在此對(duì)AddressSanitizer算法做一個(gè)簡(jiǎn)短的介紹。AddressSanitizer主要包括兩部分:插樁(Instrumentation)和動(dòng)態(tài)運(yùn)行庫(kù)(Run-time library)。插樁主要是針對(duì)在llvm編譯器級(jí)別對(duì)訪問(wèn)內(nèi)存的操作(store,load,alloca等),將它們進(jìn)行處理。動(dòng)態(tài)運(yùn)行庫(kù)主要提供一些運(yùn)行時(shí)的復(fù)雜的功能(比如poison/unpoison shadow memory)以及將malloc,free等系統(tǒng)調(diào)用函數(shù)hook住。其實(shí)該算法的思路很簡(jiǎn)單,如果想防住Buffer Overflow漏洞,只需要在每塊內(nèi)存區(qū)域右端(或兩端,能防overflow和underflow)加一塊區(qū)域(RedZone),使RedZone的區(qū)域的影子內(nèi)存(Shadow Memory)設(shè)置為不可寫(xiě)即可。具體的示意圖如下圖所示。

一文解析AddressSanitizer算法及源碼

內(nèi)存映射

AddressSanitizer保護(hù)的主要原理是對(duì)程序中的虛擬內(nèi)存提供粗粒度的影子內(nèi)存(每8個(gè)字節(jié)的內(nèi)存對(duì)應(yīng)一個(gè)字節(jié)的影子內(nèi)存),為了減少overhead,就采用了直接內(nèi)存映射策略,所采用的具體策略如下:Shadow=(Mem >> 3) + offset。每8個(gè)字節(jié)的內(nèi)存對(duì)應(yīng)一個(gè)字節(jié)的影子內(nèi)存,影子內(nèi)存中每個(gè)字節(jié)存取一個(gè)數(shù)字k,如果k=0,則表示該影子內(nèi)存對(duì)應(yīng)的8個(gè)字節(jié)的內(nèi)存都能訪問(wèn),如果0

一文解析AddressSanitizer算法及源碼

圖1: 虛擬地址映射圖

一文解析AddressSanitizer算法及源碼

插樁

為了防止buffer overflow,需要將原來(lái)分配的內(nèi)存兩邊分配額外的內(nèi)存Redzone,并將這兩邊的內(nèi)存加鎖,設(shè)為不能訪問(wèn)狀態(tài),這樣可以有效的防止buffer overflow(但不能杜絕buffer overflow)。一下是在棧中插樁的一個(gè)例子。

未插樁的代碼:

一文解析AddressSanitizer算法及源碼

插樁后的代碼:

一文解析AddressSanitizer算法及源碼

動(dòng)態(tài)運(yùn)行庫(kù)

在動(dòng)態(tài)運(yùn)行庫(kù)中將malloc/free函數(shù)進(jìn)行了替換。在malloc函數(shù)中額外的分配了Redzone區(qū)域的內(nèi)存,將與Redzone區(qū)域?qū)?yīng)的影子內(nèi)存加鎖,主要的內(nèi)存區(qū)域?qū)?yīng)的影子內(nèi)存不加鎖。

free函數(shù)將所有分配的內(nèi)存區(qū)域加鎖,并放到了隔離區(qū)域的隊(duì)列中(保證在一定的時(shí)間內(nèi)不會(huì)再被malloc函數(shù)分配)。

AddressSanitizer源碼分析

AddressSanitizer主要有三種層面的變量:Stack Variable(局部變量),Global Variable, Heap Variable。由于每種變量的生命周期(life time)不同,所以對(duì)不同種類的變量處理也是不同的。下面分別從Global Variable,Stack Variable,Heap Variable三個(gè)層次來(lái)分析AddressSanitizer源碼的邏輯結(jié)構(gòu)。

Global Variable

Global Variable存放在程序的數(shù)據(jù)段。在該算法的實(shí)現(xiàn)過(guò)程中,處理GlobalVariale的是AddressSanitizerModule類,該類繼承自llvm的ModulePass,所以我們先看一下AddressSanitizerModule類的runOnModule(Module &M)方法的處理過(guò)程,該過(guò)程首先進(jìn)行一些初始化,然后我們可以看到對(duì)Global的插樁方法InstrumentGlobals()方法。

一文解析AddressSanitizer算法及源碼

圖2: RunOnModule

在InstrumentGlobals()方法中,主要是分成兩步:首先,重新聲明一個(gè)GlobalVariable,這個(gè)GlobalVariable包含以前的GlobalVariable和一個(gè)RedZone;然后,調(diào)用runtime-library將新聲明的這個(gè)GlobalVariable的RedZone區(qū)域加鎖。我們先來(lái)看第一步的具體實(shí)現(xiàn),如圖3所示。

一文解析AddressSanitizer算法及源碼

圖3: 生成包含RedZone的新的GlobalVariable

下面,我們首先看一下一個(gè)Struct結(jié)構(gòu),該結(jié)構(gòu)記錄GlobalVariable存儲(chǔ)的首地址,數(shù)據(jù)的大小,Redzone的大小,Module的名字等信息,便于在Runtime-library中使用。該結(jié)構(gòu)在AddressSanitizerModule和runtime-library中都有相應(yīng)的定義:

一文解析AddressSanitizer算法及源碼

一文解析AddressSanitizer算法及源碼

然后我們可以看到對(duì)GlobalVariable進(jìn)行插樁來(lái)實(shí)現(xiàn)RedZone的Poison和整個(gè)GlobalVariable的Poison操作。

一文解析AddressSanitizer算法及源碼

一文解析AddressSanitizer算法及源碼

具體的Poison RedZone和Poison GlobalVariable的實(shí)現(xiàn)在Runtime-library中:

一文解析AddressSanitizer算法及源碼

一文解析AddressSanitizer算法及源碼

Stack Variable

Stack Variable保存在棧區(qū),在棧中的數(shù)據(jù)我們需要控制好變量的聲明周期(lifetime),當(dāng)調(diào)用一個(gè)函數(shù)時(shí),會(huì)開(kāi)辟一個(gè)棧,棧中的數(shù)據(jù)會(huì)有相應(yīng)的redzone和shadow memory,并將redzone的shadow memory Poison,當(dāng)函數(shù)結(jié)束(正常返回,異常),棧被銷毀,需要將數(shù)據(jù)和redzone清空,其相應(yīng)的shadow memory也要UnPoison掉。

對(duì)于Stack Variable,AddressSanitizer算法中實(shí)現(xiàn)了AddressSanitizer類,該類是繼承了llvm的FunctionPass,該P(yáng)ass能夠處理每一個(gè)函數(shù),在處理每個(gè)函數(shù)的時(shí)候,處理每一個(gè)load,store等能夠訪問(wèn)內(nèi)存的指令,在這些指令執(zhí)行前進(jìn)行插樁,看其訪問(wèn)的內(nèi)存是不是被poison。

下面我們主要看一下AddressSanitizer::runOnFunction(Module &M)函數(shù)中主要的插樁過(guò)程。

一文解析AddressSanitizer算法及源碼

在每次訪問(wèn)內(nèi)存時(shí),都會(huì)查看影子內(nèi)存的值,看其是否是0,如果是0則表示都能訪問(wèn)具體的插樁在instrumentMop函數(shù)中,

一文解析AddressSanitizer算法及源碼

其中具體的處理過(guò)程在instrumentAddress函數(shù)中:

一文解析AddressSanitizer算法及源碼

Heap Variable

Heap Variable保存在堆區(qū),其分配的函數(shù)是malloc函數(shù),該部分的主要代碼在runtime-library中,該庫(kù)中主要是先將malloc的庫(kù)函數(shù)hook住,然后自己定義malloc函數(shù),定義分配策略。

一文解析AddressSanitizer算法及源碼

具體的分配策略定義在compiler-rt/lib/asan/asan-allocator.cc文件中,感興趣可以看一下。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Google
    +關(guān)注

    關(guān)注

    5

    文章

    1752

    瀏覽量

    57333

原文標(biāo)題:AddressSanitizer算法及源碼解析

文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    【安全算法之DES】DES算法的C語(yǔ)言源碼實(shí)現(xiàn)

    【安全算法之DES】DES算法(支持ECB/CBC模式)的C語(yǔ)言源碼實(shí)現(xiàn)
    的頭像 發(fā)表于 09-20 08:58 ?4535次閱讀
    【安全<b class='flag-5'>算法</b>之DES】DES<b class='flag-5'>算法</b>的C語(yǔ)言<b class='flag-5'>源碼</b>實(shí)現(xiàn)

    Spark運(yùn)行架構(gòu)與源碼解析

    Spark 源碼解析DAGScheduler中的DAG劃分與提交
    發(fā)表于 04-24 06:32

    PID算法解析,絕對(duì)實(shí)用

    PID算法解析,絕對(duì)實(shí)用
    發(fā)表于 01-21 07:40

    解析Memory安全和硬件Memory Tagging技術(shù)(2)

    現(xiàn)有的工具和實(shí)踐編程實(shí)踐和測(cè)試工具減少了內(nèi)存bug的可能性。測(cè)試驅(qū)動(dòng)的開(kāi)發(fā)流程和如AddressSanitizer或Valgrind的動(dòng)態(tài)測(cè)試工具起可以幫助避免內(nèi)存bug. Fuzzing
    發(fā)表于 08-18 11:24

    PID控制算法C語(yǔ)言源碼

    PID控制算法C語(yǔ)言源碼包括程序源碼以及數(shù)據(jù)仿真結(jié)果。
    發(fā)表于 12-02 15:33 ?27次下載

    源碼-易語(yǔ)言常用算法

    易語(yǔ)言是門以中文作為程序代碼編程語(yǔ)言學(xué)習(xí)例程:易語(yǔ)言-源碼-易語(yǔ)言常用算法
    發(fā)表于 06-06 17:43 ?4次下載

    178個(gè)與算法有關(guān)的C語(yǔ)言源碼

    178個(gè)與算法有關(guān)的C語(yǔ)言源碼源碼很好,無(wú)論對(duì)初學(xué)者還是老程序員都有幫助。下載后好好學(xué)習(xí)吧。
    發(fā)表于 08-18 18:00 ?11次下載

    Uboot中start.S源碼的指令級(jí)的詳盡解析

    Uboot中start.S源碼的指令級(jí)的詳盡解析
    發(fā)表于 10-30 08:47 ?28次下載
    Uboot中start.S<b class='flag-5'>源碼</b>的指令級(jí)的詳盡<b class='flag-5'>解析</b>

    基于java的負(fù)載均衡算法解析源碼分享

    負(fù)載均衡的算法實(shí)際上就是解決跨系統(tǒng)調(diào)用的時(shí)候,在考慮后端機(jī)器承載情況的前提下,保證請(qǐng)求分配的平衡和合理。下面是基于java的負(fù)載均衡算法解析源碼,以供參考。
    發(fā)表于 01-01 19:29 ?2190次閱讀

    解析PLC的應(yīng)用

    解析PLC的應(yīng)用,具體的跟隨小編起來(lái)了解下。
    的頭像 發(fā)表于 07-19 11:21 ?5192次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>文</b><b class='flag-5'>解析</b>PLC的應(yīng)用

    基于EAIDK的人臉算法應(yīng)用-源碼解讀(2)

    期介紹了基于EAIDK的人臉算法應(yīng)用,本期從應(yīng)用角度,解讀下該案例源碼。本期案例源碼解讀,主要從
    的頭像 發(fā)表于 12-10 21:14 ?820次閱讀

    Navigation源碼解析

    Navigation源碼解析 谷歌推出Navigation主要是為了統(tǒng)應(yīng)用內(nèi)頁(yè)面跳轉(zhuǎn)行為。本文主要是根據(jù)Navigation版本為2.1.0 的源碼進(jìn)行講解
    的頭像 發(fā)表于 06-15 16:38 ?1706次閱讀

    簡(jiǎn)述hex文件解析源碼

    簡(jiǎn)述hex文件解析源碼
    發(fā)表于 09-12 09:20 ?8次下載

    云海計(jì)費(fèi)系統(tǒng)v4.1 視頻解析解析收費(fèi)接口專用 短視頻解析解析收費(fèi)接口專用 影視視頻電影解析計(jì)費(fèi)平臺(tái)源碼程序

    介紹:云海計(jì)費(fèi)系統(tǒng)v4.1 視頻解析 短視頻解析 影視視頻電影解析計(jì)費(fèi)平臺(tái)源碼程序云海解析計(jì)費(fèi)系統(tǒng)是
    發(fā)表于 01-11 16:02 ?13次下載
    云海計(jì)費(fèi)系統(tǒng)v4.1 視頻<b class='flag-5'>解析</b><b class='flag-5'>解析</b>收費(fèi)接口專用 短視頻<b class='flag-5'>解析</b><b class='flag-5'>解析</b>收費(fèi)接口專用 影視視頻電影<b class='flag-5'>解析</b>計(jì)費(fèi)平臺(tái)<b class='flag-5'>源碼</b>程序

    Java算法大全源碼包開(kāi)源源碼

    Java算法大全源碼包開(kāi)源源碼
    發(fā)表于 06-07 14:58 ?1次下載