• 
    

    
    

      99热精品在线国产_美女午夜性视频免费_国产精品国产高清国产av_av欧美777_自拍偷自拍亚洲精品老妇_亚洲熟女精品中文字幕_www日本黄色视频网_国产精品野战在线观看

      ?

      面向大規(guī)模源代碼的內(nèi)存安全性動態(tài)分析技術

      2021-08-02 03:35:28沖,孫毅,仵
      計算機技術與發(fā)展 2021年7期
      關鍵詞:插樁指針語句

      王 沖,孫 毅,仵 俊

      (南京航空航天大學 計算機科學與技術學院,江蘇 南京 211100)

      0 引 言

      C語言常用于諸如操作系統(tǒng)、嵌入式軟件系統(tǒng)等對性能要求較高的系統(tǒng)的編寫。然而C語言本身缺乏對內(nèi)存安全性檢測的相關功能,因此使用其編寫的程序可能存在較為嚴重的內(nèi)存安全性漏洞[1-5]。動態(tài)分析[6-8]是目前常用的對程序進行內(nèi)存安全檢測的方法,目前常用的實現(xiàn)方法有二進制代碼插樁、中間代碼插樁、源代碼插樁[9-10]等。

      二進制代碼插樁是對可執(zhí)行程序進行插樁,優(yōu)點是不需要源代碼就可以對程序進行動態(tài)分析;中間代碼插樁是對編譯后的代碼插樁,可以利用優(yōu)化,減少不必要的插樁;源代碼插樁是指對源碼上進行修改,添加行為監(jiān)代碼,對程序進行檢測,優(yōu)點是可以獲取源代碼中的位置,準確地報告錯誤信息。

      為了能更準確有效地檢測程序的錯誤并能將錯誤的變量信息準確地反饋給用戶,該文采用了源代碼插樁技術進行插樁,并在基于指針技術[11-13]的基礎上,借助開源編譯器Clang和C++語言實現(xiàn)了內(nèi)存安全分析工具Movec,完成其對大規(guī)模C程序的內(nèi)存安全性檢測,并通過實驗進行了驗證,表明該內(nèi)存分析工具對大規(guī)模程序的內(nèi)存檢測是有效且高效的。

      1 基礎知識

      基于指針的內(nèi)存安全性檢測技術的主要思想是對程序中的所有指針變量構造一個指針元數(shù)據(jù),用來記錄該指針的內(nèi)存狀態(tài)、上下界以及指向當前內(nèi)存的指針的個數(shù)。然后,當指針賦值或者以函數(shù)參數(shù)傳遞的時候,更新這個指針的元數(shù)據(jù),用來保持數(shù)據(jù)的一致性。最后,在對指針進行解引用或者通過指針對內(nèi)存進行讀寫時,根據(jù)指針元數(shù)據(jù)中記錄的內(nèi)存狀態(tài)信息,來判斷該次內(nèi)存訪問是否是合法的,從而檢測出內(nèi)存的安全性。

      采用源代碼插樁實現(xiàn)基于指針內(nèi)存安全性檢測的過程分為三個部分:一是對指針變量定義進行插樁以初始化元數(shù)據(jù),對指針變量賦值進行插樁來更新元數(shù)據(jù)的信息;二是在指針解引用的時候來檢查該指針所引用的對象的元數(shù)據(jù);三是對函數(shù)定義進行插樁以初始化函數(shù)參數(shù)的元數(shù)據(jù)、計算存儲返回值的元數(shù)據(jù)。然后,對函數(shù)定義生成一個包裝函數(shù),該包裝函數(shù)用來對程序檢測并傳遞指針元數(shù)據(jù)。接著,對原函數(shù)調用重命名,并插入元數(shù)據(jù),然后將原函數(shù)調用重定向到其包裝函數(shù)來完成檢測。

      2 大規(guī)模C程序的內(nèi)存安全性檢測的研究與實現(xiàn)

      2.1 項目插樁的改進

      目前的源代碼插樁工具對程序的插樁一般有兩種模式,一種是單文件插樁模式,一種是項目插樁模式。單文件插樁模式適用于一些文件數(shù)量比較少的情況。對于項目插樁模式,目前常采用的方法是使用搜索后綴的方法將文件中所有的.c和.h文件進行搜索,然后將所有的文件添加到插樁列表中,把每個.c和.h文件都當成一個翻譯單元進行解析插樁,插樁完成后將新的文件生成到目標文件夾中。這種方法在對大規(guī)模的程序進行插樁時過于簡單,會導致如下問題:一對每個.c和.h文件進行搜索,會將一些不必要的文件進行搜索并插樁,增加了項目插樁時間;二是當文件編譯命令中使用了-D定義了宏或者使用-I頭文件目錄時,這種項目插樁的方式獲取到的語法樹會和原語法樹完全不同,導致插樁錯誤;三是當項目中的頭文件出現(xiàn)一個不完整文件時,將該文件當作一個完整的翻譯單元處理時,無法獲取其完整的語法樹,導致程序插樁失敗。

      對于問題一和問題二,該文利用編譯數(shù)據(jù)庫的概念,對源代碼插樁工具的項目插樁模式進行改進。編譯數(shù)據(jù)庫是在項目實際編譯過程中對編譯器調用的監(jiān)控記錄,其中包含了每個文件在編譯時的編譯選項。利用編譯數(shù)據(jù)庫獲取待插樁文件的存儲路徑和該文件對應的編譯指令,構造出每個文件的原始編譯命令,從而在對文件進行解析時獲取到的語法樹和原始語法樹是一致的。同時,通過編譯數(shù)據(jù)庫,可以獲取一個可執(zhí)行文件的所有的依賴文件,不需要進行.c和.h的搜索,降低了程序插樁的時間。

      對于問題三,該文提供的解決方法是將不完整頭文件擴展到源文件中,不再對該頭文件進行單獨插樁。因此,該文提供了一個頭文件擴展算法,該算法可以將指定的文件進行擴展,當遇到該文件時,不對其插樁,同時將其內(nèi)容擴展到所有引入該頭文件的文件中。當對程序進行內(nèi)存安全性檢測時,由于系統(tǒng)庫文件中的接口是編譯器提供的標準接口,不需要對其進行插樁檢測,所以該文提供的頭文件擴展算法對所有的系統(tǒng)庫文件不進行擴展,這不僅減少了對程序的插樁時間,也減少了代碼的膨脹率。同時,該文提供的算法還支持不擴展用戶指定的頭文件。

      該算法的主要思想是:首先,創(chuàng)建一個文件輸出流,然后利用Clang前端接口創(chuàng)建一個原始詞法解析器,該解析器只解析當前主文件中的內(nèi)容,然后當解析到#include指令時,在頭文件列表中查找該include的文件標識,然后判斷該文件是否是系統(tǒng)庫文件,若不是,則將其內(nèi)容寫入到輸出流,同時遞歸地調用本方法去繼續(xù)擴展頭文件中引入的頭文件。若是系統(tǒng)庫文件則保持不變,繼續(xù)解析下一個#include命令。其中,頭文件列表是當讀取的文件發(fā)生切換時記錄的,它通過Clang提供的PPCallbacks中的FileChanged()回調函數(shù)記錄,每當文件發(fā)生切換,記錄該文件的ID、類型等信息。當一個文件中所有的#include指令的內(nèi)容擴展完成后,再將#include指令后的內(nèi)容寫入到輸出流,最后寫回到原文件中,從而實現(xiàn)對頭文件的擴展。具體實現(xiàn)如圖1所示。

      圖1 頭文件擴展算法

      2.2 包裝函數(shù)插樁改進算法

      基于指針的內(nèi)存安全性動態(tài)分析技術對包含指針參數(shù)或返回值為指針類型的函數(shù),需要對其插樁包裝函數(shù),用來初始化函數(shù)參數(shù)和返回值變量的指針元數(shù)據(jù)。對函數(shù)定義生成其包裝函數(shù)定義,然后在其函數(shù)調用中重命名該方法,將其定位到包裝函數(shù)以完成內(nèi)存檢測。但是由于庫函數(shù)的定義在系統(tǒng)頭文件中,無法根據(jù)其定義生成包裝函數(shù)。通常,內(nèi)存分析工具會提供常用庫函數(shù)的包裝函數(shù),但是當程序調用的庫函數(shù)較多或者使用了第三方庫時,內(nèi)存分析工具無法提供所有的庫函數(shù)的包裝函數(shù)。若沒有提供包裝函數(shù)的庫函數(shù),則會對其進行插樁,此時會因為找不到包裝函數(shù)定義而導致編譯失敗。針對這類問題,該文提供的解決方法是:首先,對于一個函數(shù),判斷其是否是庫函數(shù),然后判斷該函數(shù)的包裝函數(shù)工具是否提供,若提供了其包裝函數(shù),則對該庫函數(shù)進行插樁,若不提供,則不對該庫函數(shù)進行插樁。

      因此該文給出一個庫函數(shù)判斷算法,該算法的思想根據(jù)是庫文件是存儲在系統(tǒng)特定位置下,通過判斷一個函數(shù)所引用的聲明的文件是否在當前工作目錄中,來判斷該函數(shù)是否為庫函數(shù)。具體的實現(xiàn)如圖2所示。

      圖2 庫函數(shù)判斷算法

      當判斷一個函數(shù)是庫函數(shù)后,此時需要判斷函數(shù)是否需要插樁,該文利用Clang獲取用戶文件語法樹,然后通過函數(shù)聲明與定義訪問函數(shù)VisitFunctionDecl記錄下每一個函數(shù)名,將其傳遞給插樁模塊,配合系統(tǒng)提供的包裝函數(shù)列表,完成函數(shù)是否需要插樁的判定。

      2.3 匿名結構體插樁改進

      對于結構體指針解引用,需要獲取該指針指向區(qū)域的上界和下界。對于指向命名結構體的指針變量如struct st *ptr,它指向區(qū)域的上界和下界分別為ptr和ptr+sizeof(struct st)。但是對于匿名結構體,無法獲取它的名字,所以sizeof的括號中缺少結構體名字,導致插樁后的程序出現(xiàn)編譯錯誤,如:struct {int a; int b;} *ptr;對*ptr插樁后獲取的下界ptr+sizeof(struct(anonymous struct at /home/a.c:3:1)。

      對于該問題,該文提供的解決方法是:對匿名結構體添加一個唯一的ID,在使用sizeof獲取匿名結構體變量類型的時候,使用該ID構造函數(shù)的名字,通過該名字確定結構體類型的大小。使用AST上該結構體定義節(jié)點的地址作為ID。在結構體定義時添加有該ID構造的名字,然后在訪問該結構體變量時獲取該變量的結構體定義節(jié)點,并獲取其地址,從而保證了構造的ID是唯一的并且是一致的。具體的實現(xiàn)算法如圖3所示。

      圖3 匿名結構體插樁算法

      2.4 循環(huán)結構和switch分支結構的改進

      當一個指針無效時,需要對該指針的元數(shù)據(jù)進行清除,以節(jié)省空間和時間。在循環(huán)結構中包含break語句和continue語句,switch分支結構中包含break語句,這些語句會改變程序的執(zhí)行流程,所以需要對break語句和continue語句進行重寫,來實現(xiàn)對程序的指針元數(shù)據(jù)的清除,具體重寫的規(guī)則如下:

      循環(huán)中的break替換為:{bc_flag_LOOP_BLOCK_ID=1;goto PRFlbl_THIS_BLOCK_ID;}。

      continue語句替換為:{bc_flag_LOOP_BLOCK_ID=2;goto PRFlbl_THIS_BLOCK_ID;}。

      switch中的break替換為:{bc_flag_SWIT_BLOCK_ID=1;goto PRFlbl_THIS_BLOCK_ID;}。

      其中bc_flag_LOOP_BLOCK_ID值為1時表示循環(huán)中的break語句,值為2時表示continue語句,bc_flag_SWIT_BLOCK_ID表示switch語句中的break語句。LOOP_BLOCK_ID表示該循環(huán)語句塊的ID,SWIT_BLOCK_ID表示語句switch語句塊的ID,lbl_THIS_BLOCK_ID插入在該語句塊最后用來清除在該語句塊內(nèi)定義的元數(shù)據(jù),然后再根據(jù)bc_flag判斷執(zhí)行流程。

      在對break的替換的時候,需要考慮一些復雜結構,如循環(huán)中嵌套switch結構或switch語句中嵌套循環(huán)結構,此時插樁時需要對該break語句進行判斷來實現(xiàn)不同的替換。針對該問題,該文提出的解決方法是:對于一個break語句,在插樁前需要記錄它的父語句塊PBS,在進行函數(shù)插樁時記錄循環(huán)結構語句塊LBS和switch語句塊SBS,如果不存在循環(huán)結構或switch結構體,則LBS和SBS為空。然后通過比較break語句父語句塊PBS和LBS、SBS的關系,判斷出break語句是屬于循環(huán)結構還是屬于switch分支結構,從而根據(jù)對應的方法對break語句替換,以保證程序在清除完元數(shù)據(jù)之后能正常運行。具體的算法如圖4所示。

      圖4 break語句插樁算法

      3 工具實現(xiàn)

      該文所述的對大規(guī)模C程序的應用理論在內(nèi)存動態(tài)分析Movec上進行了實現(xiàn)。該工具實現(xiàn)采用的是基于Clang編譯器來對源代碼進行檢測邏輯的插樁,插樁過后的代碼仍然是標準C程序。同時,保證了改進過的Movec能正常地插樁和檢測大規(guī)模C程序。其架構如圖5所示。

      圖5 Movec架構

      在對大規(guī)模程序內(nèi)存安全性進行分析時,Movec的輸入是待檢測項目和一個編譯數(shù)據(jù)庫文件,即JSON文件,輸出是插樁完整的項目Movec對該JSON進行解析,并構造出完整的文件編譯規(guī)則,將其傳遞給C解析器,構造每個文件的抽象語法樹。最后通過AST visitor對語法樹進行訪問,在語法樹上獲取需要插樁的節(jié)點位置,通過Clang提供的SourceManager接口和Rewriter接口實現(xiàn)內(nèi)容的獲取和重寫,完成對包裝函數(shù)的插樁改進實現(xiàn),對匿名結構體的插樁實現(xiàn)以及對break語句改進的實現(xiàn),完成對項目的源代碼插樁。將該文提出的插樁改進規(guī)則應用到Movec工具上,使其能有效地對大規(guī)模C程序進行插樁,并對其進行動態(tài)內(nèi)存分析。

      4 實驗與分析

      基于上面介紹的算法,將其在Movec上進行了實現(xiàn)。本節(jié)將介紹優(yōu)化后的Movec對大規(guī)模程序分析的有效性和高效性。

      4.1 有效性實驗

      為了驗證改進部分插樁規(guī)則后工具的有效性,將Movec應用到Mibench標準測試集上。實驗平臺為64位的Ubuntu16.04操作系統(tǒng),處理器為Intel(R) Core(TM) i5-7200U CPU 2.70 GHz,內(nèi)存是8.00 GB,編譯器為gcc4.8.2。

      選取了其中8個大規(guī)模的測試集進行實驗,并與SoftBoundCets[14]、ASan[15]、Valgrind[16]進行了對比。通過實驗表明,Movec可以正確地對這8個大規(guī)模的測試集進行安全檢測。Movec和ASan在blowfish、jpeg、rijndael和rsynth中檢測出了錯誤,但是Movec還檢測出了ASan未檢測出的錯誤,如在blowfish中的數(shù)組訪問越界錯誤:

      void BF_set_key(key, int len, unsigned char* data){

      unsigned char * end=&(data[len]);}

      unsigned char ukey[8];

      BF_set_key(&key,8,ukey);

      而SoftBoundCets則對5個測試集無法正常插樁,并且其余三個沒有檢測出錯誤。Valgrind正常對程序檢測,但未發(fā)現(xiàn)任何錯誤。

      通過結果表明,Movec對大規(guī)模程序的檢測是有效的,且沒有發(fā)生漏報和誤報。

      4.2 性能實驗

      本節(jié)將Movec與內(nèi)存檢測工具SoftBoundCets、ASan、Valgrind進行性能對比。從Mibench中選取了規(guī)模較大的8個測試集進行對比驗證,考慮到誤差,選用了三次實驗結果去平均值的方式。實驗結果如表1所示。

      表1 運行時間對比結果

      綜合表中數(shù)據(jù)可以看出,SoftBoundCet由于使用了靜態(tài)分析,其在gsm和blowfish(l)優(yōu)于Movec,但它僅僅只能在其中三個測試集中運行成功;Valgrind采用的二進制代碼插樁,雖然可以成功運行在大規(guī)模C程序上,但運行時間遠遠超過Movec;ASan在gsm和lame上的性能優(yōu)于Movec,但是當在檢測出錯誤的測試集中(如blowfish、jpeg、rijndael、rsynth),Movec的性能是好于ASan的。Movec還可以設置在發(fā)現(xiàn)錯誤后繼續(xù)運行,可以檢測出整個程序中可能存在的內(nèi)存錯誤,而ASan和SoftBoundCets在發(fā)生錯誤后立即終止,導致后面的錯誤無法正常檢測。

      由以上分析結果可以看出,改進后的Movec不僅能夠正確地在所有Mibench上運行,而且在有效性和高效性上都是優(yōu)于其他工具的,是一個可靠的大規(guī)模C程序內(nèi)存安全分析工具。

      5 結束語

      對大規(guī)模C程序進行動態(tài)內(nèi)存分析時可能出現(xiàn)的問題進行了描述,并給出了相應的解決方法,然后將其在內(nèi)存動態(tài)分析工具Movec上進行了實現(xiàn),使其能對大規(guī)模C程序進行內(nèi)存安全性檢測。通過實驗,表明Movec不僅能有效地對大規(guī)模C程序進行檢測,同時在綜合性能上是更優(yōu)的。在接下來的工作中,將繼續(xù)優(yōu)化其對大規(guī)模程序檢測的運行時間,例如結合靜態(tài)分析,以減少對程序不必要的插樁和檢測。

      猜你喜歡
      插樁指針語句
      基于TXL的源代碼插樁技術研究
      重點:語句銜接
      偷指針的人
      娃娃畫報(2019年5期)2019-06-17 16:58:10
      基于性能分析的自適應插樁框架
      基于記錄重播的嵌入式系統(tǒng)死鎖檢測方法
      軟件導刊(2017年12期)2018-01-09 13:01:23
      精彩語句
      為什么表的指針都按照順時針方向轉動
      基于改進Hough變換和BP網(wǎng)絡的指針儀表識別
      電測與儀表(2015年5期)2015-04-09 11:30:42
      基于順序塊的嵌入式白盒測試插樁技術研究
      ARM Cortex—MO/MO+單片機的指針變量替換方法
      盐山县| 手游| 永平县| 惠来县| 右玉县| 九寨沟县| 富阳市| 承德县| 都江堰市| 琼海市| 万安县| 库车县| 石楼县| 沐川县| 旌德县| 水富县| 霸州市| 刚察县| 海门市| 达州市| 娱乐| 绥棱县| 长葛市| 镇康县| 金平| 津南区| 逊克县| 禹城市| 平乐县| 策勒县| 高淳县| 宜丰县| 千阳县| 岗巴县| 周至县| 红河县| 沾益县| 台江县| 巨鹿县| 静宁县| 富源县|