C語言中的指針機制使得它靈活高效,但由於指針操作不當產生的動態記憶體錯誤也有很多,比如記憶體泄漏(Memory Leakage)、記憶體的重複釋放、空指針解引用(NullPointer Dereference)。其中空指針引用是一類普遍存在的記憶體故障,當指針指向無效記憶體地址時對其引用,有可能產生不可預見的錯誤,導致軟體系統崩潰。空指針引用缺陷可能導致系統崩溴、拒絕服務等諸多不良後果。因此,消除軟體中的空指針引用缺陷將是一件具有價值的工作。
基本介紹
- 中文名:空指針引用故障
- 外文名:Null Pointer Dereference
定義,危害,指針分析技術,檢測方法,檢測工具,
定義
空指針引用故障(Null Pointer Dereference),也叫空指針解引用,是程式設計語言中一類常見的動態記憶體錯誤。指針變數可以指向堆地址、靜態變數和空地址單元 ,當引用指向空地址單元的指針變數時,就會產生空指針引用故障,有可能產生不可預見的錯誤,導致軟體系統崩。
危害
中國國家信息安全漏洞庫(CNNVD)統計,2013年共發現空指針引用引發的漏洞共35個,這些漏洞存在於作業系統、伺服器應用程式等軟體系統中,漏洞類型有拒絕服務、代碼注入、信息泄露、—區溢出、數字錯誤等。這些漏洞一旦被惡意攻擊者利用,可能導致系統崩潰,伺服器程式可能會拒絕服務,或者機密信息泄露,這都將嚴重的影響軟體的運行以及系統的安全。
根據我們對國內航天、航空、武器裝備、金融、電信等數千萬行國產軟體套用DTSC的測試報告統計,在所有故障類缺陷中,空指針引用缺陷大約會占到30%左右,空指針引用缺陷的密度大致是0.3個/KLOC。
MicrosoftWindows針對傳遞給windows核心系統調用的註冊鍵值沒有進行充分的校驗,攻擊者通過運行特殊構建的應用程式,使核心觸發空指針引用而造成系統崩饋。MicrosoftSMB協定軟體在處理SMB報文中的share和servername欄位時存在空指針引用錯誤,未經認證的攻擊者可以通過向運行Server服務的計算機傳送特製網路訊息來利用該漏洞,導致受影響系統停止回響,直至手動重新啟動。
Linux Kernel是Linux所使用的核心,Linux Kernel 的 kemel/posix-timers.c 檔案中的 clock—nanosleep()函式存在安全漏洞,如果使用等於CLOCK_MONOTONIC—RAW的時鐘ID調用該函式就會觸發空指針引用,導致拒絕服務的情況。deep—rev—state_process()函式在關閉了套接字後仍然允許接受,關閉後重置沒有阻止對己經廢棄套接字的操作,可造成空指針引用。Linux Kernel沒有正確地執行tty操作,本地用戶可以在目錄drivers/net/的以下檔案中觸發空指針引用,導致系統崩饋。
指針分析技術
指針分析的目標是確定每個指針在運行時的指向。與其它靜態分析一樣,指針分析也是一個不可判定問題。即便是對程式做出某種限制(例如限制動態記憶體分配、忽略分支條件)以便易於處理,指針分析依然是一個NP難的問題;特別是指針間存在別名、複雜數據結構類型、指針計算、函式指針等更加劇了指針分析的難度;因此,為達到分析精度與效率的平衡,指針分析時需要作某種程度的近似。
進行指針分析首先要確定指針指向信息的表示形式,指針指向信息的表示形式對指針分析算法的精度與效率有很大的影響。指向信息的表示通常有兩種:storeless方法和store based方法。Storeless方法是以別名對(Alias Pair)的方式表示指針分析結果;但是當分析的程式中有遞歸的數據結構時,別名對構成的集合可能是一個無窮集,為此需要採取一些損失精度的處理。Store based方法使用圖的方式表示分析結果,如指向圖(Points-to Graph) 別名圖(Alias Graph) 、存儲圖(StoreGraph) 等。
指針分析的精度主要體現在:在過程內分析中是否考慮程式中的語句執行順序,在過程間的分析中是否考慮過程調用的上下文信息,在對複雜數據結構的數據分析時是否把每個成員看作,在基於控制流分析時是否考慮在匯合節點不同的路徑的合併,在對面向對象語言程式分析時是否考慮同一個類的不同實例化對象。
流不敏感的分析不考慮語句執行順序,流敏感的分析區分語句的執行順序與控制流信息;前者對整個方法只生成一個指針的指向關係表示,後者在每個語句處會生成一個分析圖。流敏感的指針分析能夠對指針的指向進行強更新,因此能夠更精確的描述指針指向的信息。流不敏感的指針指向分析研究方向主要分為兩個方面:一個是基於Andersen算法_的擴展;另一個是基於Steensgaard算法丨的擴展。Andersen利用包含約束集使得指向分析的結果更精確;Steensgaard通過建立一種統一的類型推導模型,精度不如前者,卻擁有接近線性的時間複雜度。傳統的流敏感指針分析是在控制流圖上進行標準的疊代分析,在每個可達的程式點上對指針指向信息進行分析求得不動點,通過在每個節點上消除掉不需要的指向信息,從而得到比流不敏感分析更精確的結果。但傳統的流敏感指針分析存在的問題。(1)分析時在控制流上傳遞了過多指針信息,因為只有部分指針信息被後續節點使用;(2)因為指針指向信息比數據流分析的數值信息複雜,簡單的借鑑數據流分析技術來分析指針導致效率低下;(3)每個節點都保存指向信息,分析大型程式時將會耗用大量記憶體資源。為克服傳統流敏感分析在效率方面的不足。近來,有些研究對指針進行稀疏的流敏感分析該類分析技術主要是套用靜態單賦值(Static singleassignment)表示程式中變數的定義-使用關係,在控制流圖節點上對只對需要進行指針分析的節點進行分析,並用二元決策圖表示指針的指向信息以更高效的實現對指針進行強更新操作。稀疏分析能夠大大提升分析的效率,但是如何跟數據流分析結合是該方法需要結合的問題。
過程間指針分析時的兩個核心問題是:傳入的指針指向信息如何映射成被調用函式的指針指向信息,被調用函式出口處的指針指向信息如何反映射到調用點。上下文不敏感的分析方法對同一函式的不同調用只產生一個唯一的近似結果,上下文敏感的分析方法依據同一函式不同調用點指針指向模式的不同而產生不同的分析結果。後者較前者的分析結果更加精確。最簡單有效的過程間分析是函式內聯,另一種常用的方法是記錄函式調用串來區分調用上下文。這兩種方法因為在每個調用點都進行重複展開而效率低下。基於調用關係生成調用圖,在擴展的調用圖上進行分析。該方法的思想是全路徑擴展,分析結果較為精確;但會因為路徑膨脹導致分析效率低下,難以勝任對大型程式的分析。為避免全路徑擴展與被調用函式多次分析,最常用的一種方法是通過函式摘要建立輸入與輸出間的映射關係,函式摘要描述了輸入與輸出間的映射關係以及函式副作用等信息。函式摘要的準確度將決定分析的精度。為進一步提高分析的效率,有些基於特定的需求進行有選擇的上下文敏感分析。
域敏感分析是將程式中所有複雜數據類型的每個成員變數都視作不同的存儲對象。Steensgaard本人釆用了最大公因子前綴技術來建立結構體類型之間的對應關係,根據非標準類型約束準則,利用類型推導算法對其工作進行了改進形成了支持域敏感的指向分析。Yong將Steensgaard的思想進一步擴展,給出了三種不同精度的方式解析結構體類型之間的對應關係。Pearce利用Steensgaard的最大公因子前綴思想改進了 Andersen的算法其對結構體的域成員給出了不同於Yong的表示方法,利用域地址模型來代替整數偏移模型,效率有所提高。除了Steensgaard的算法提出的擴展外,比較流行的還有基於偏移表示的分析方法。Stocks認為所有代碼都是一種基於偏移的形態對重疊域的計算雖然可以更精確的表示其別名關係,但只計算匹配域便可滿足別名分析的精度要求。Wilson為每一個對象保留一個步長,用於記錄它的偏移,這種方法對於結構體中包含數組指針的處理有較好的效果。另外,還有一些算法把結構體的域作為區分單元,利用三元模型對其進行建模,但並沒有實際的對其進行數據流計算或者計算的不夠精確。
路徑敏感分析利用控制語句的表達式限制可能的值進入不同的分支語句。例如在數據流分析過程中加入路徑標籤實現了路徑敏感的指針指向分析,但其分析效率相對較低,影響了該技術在實際套用中的可擴展性。SPAS在全稀疏分析的基礎上進行了可擴展的路徑敏感的指針分析。
上述的各種敏感技術的運用與否,決定著測試的精度與效率。其中最重要的是上下文敏感與流敏感,目前的檢測工具大多套用了上下文敏感分析。
檢測方法
相關技術可粗略的分為空指針引用缺陷檢測與指針引用驗證兩大類。
前者側重於如何儘可能多的發現程式中空指針引用,後者側重於如何驗證程式中的指針是否為空。空指針引用缺陷檢測一般是在數據流分析、指針進行分析的基礎上,根據一些規則基於控制流前向的檢測。指針引用驗證技術是基於需求驅動的思想,一般是首先識別出指針,再沿著控制流後向的驗證指針是否是空,指針引用驗證也要進行數據流分析與指針分析才能實現精確的驗證。
對於空指針引用缺陷檢測,核心問題是對程式中所有可達路徑上現的指針引用,判斷其相關的指針在運行時是否指向了有效記憶體。如果要達到檢測的可靠性與充分性,首先要保證能夠識別出程式中所有可達路徑上出現的指針引用及相關指針,在對這些指針進行可靠的指針分析的基礎上進行空指針引用缺陷的檢測。如果要達到分析的完備性,則要保證所識別的指針一定是指針,所做的指針分析得到的指針狀態是肯定屬於程式運行時狀態。
檢測工具
檢測工具Julia基於數據流前向保守的靜態分析,並基於抽象釋的理論,用抽象域表示程式中的邏輯約束,將程式的具體語義轉化為抽象語義,在程式的抽象語義上通過對抽象域描述的表達式進行不動點計算,以檢測空指針引用。
檢測工具SALSA採用逐級擴展的分析策略,先對單個方法進行過程內分析進行空指針引用檢測,對不能確定的參數向該方法的調用者進行擴展分析,對不能確定的函式返回則向所調用的方法進行擴展分析,擴展的級別太深則做近似處理。
檢測工具FindBugst對指針引用總結了一些經驗規則,對不可達路徑、控制流匯合、指針賦值語句、斷言等特定情況制訂了專用的檢測規則,這些檢測規則只能檢測出特定場景下的空指針引用。
檢測工具Saturn基於約束求解的思想,對程式中的約束進行過估計與低估計求解而檢驗某種缺陷是否出現,己進行可靠的檢測;但實驗結果表明,因為沒有對指針進行形態分析而導致大量的空指針引用誤報。