Fuzzing Error Handling Code using Context-Sensitive Software Fault Injection

1、Abstract

本文主要是對錯誤處理代碼進行模糊測試,現在的模糊測試技術主要是基於生成和變異的方法來生成種子,儘可能的覆蓋代碼執行路徑,從而發現錯誤。但是在測試錯誤處理代碼方面非常有限,因爲一些錯誤處理代碼只能由偶發錯誤(例如內存不足和網絡連接故障)觸發,而不能由特定的輸入觸發。

所以在本文中作者提出了一個名爲FIFUZZ的模糊測試框架,有效的測試錯誤處理代碼。FIFUZZ的核心是上下文相關的軟件故障注入(software fault injection,SFI),該方法可以有效地覆蓋錯誤處理代碼,並且可以查找隱藏在具有複雜上下文關係的錯誤處理代碼中的深層錯誤。

最後FIFUZZ與上下文無關的SFI和現有的模糊測試工具(AFL,AFLFast,AFLSmart和FairFuzz)進行了比較, FIFUZZ發現了這些工具遺漏的許多bug。

2、Background & Introduction

2.1 錯誤處理代碼

錯誤處理代碼是指由於特殊的執行條件,例如用戶的無效輸入,內存不足和網絡連接故障,程序在運行時遇到的特殊情況。我們將這些異常情況稱爲錯誤,用於處理錯誤的代碼稱爲錯誤處理代碼。(例如try / catch中的catch內容)

另外錯誤可以分爲兩類:分別是與輸入有關的錯誤和偶發性的錯誤。與輸入相關的錯誤是由無效輸入引起的,例如異常的命令和錯誤的數據,這類錯誤可以通過提供特定的輸入來觸發,目前的模糊測試技術主要也是觸發此類錯誤。

偶發性的錯誤是由偶爾發生的異常事件引起的錯誤,例如內存不足或網絡連接失敗,此類錯誤與執行環境和系統資源(例如內存和網絡連接)的狀態有關,但與輸入無關,因此現有的模糊測試技術很難觸發該錯誤。

2.2 錯誤處理代碼的特點
  1. 錯誤處理代碼很重要,但它本身很容易出錯
  2. 錯誤處理代碼很難正確實現,因爲它通常涉及特殊和複雜的語義
  3. 錯誤處理代碼也難以測試,因爲此類代碼很少執行
  4. 錯誤處理代碼引起的關注也比較少
    由於這些特點,錯誤處理代碼中可能會存在許多bug,並且這些bug可能會有比較大的危害。另外通過作者的調研發現,許多CVE漏洞都是由錯誤處理代碼引起的(例如CVE-2019-7846,CVE-2019-2240,CVE-2019-1750和CVE-2019-1785)。
2.3 軟件故障注入(software fault injection, SFI)技術

軟件故障注入是一種運行時的測試技術,SFI故意將故障或錯誤注入到被測試程序的代碼中,然後執行該程序來測試在執行過程中是否可以正確處理注入的故障或錯誤。具體而言,將錯誤注入到能夠觸發錯誤處理代碼的sites中,我們將每個此類site稱爲一個error site。許多現有的基於SFI的方法在測試錯誤處理代碼方面都取得了不錯的效果。
void fun() {
z = malloc(…); // error site
if(!z) { // 錯誤處理代碼

}
}

2.4 已有技術檢測錯誤處理代碼
  1. 靜態分析(缺少運行時信息,經常引入許多誤報
  2. 輸入驅動的模糊測試(因爲某些代碼只能由非輸入偶然錯誤(例如內存不足和網絡連接故障)觸發,不能有效地測試錯誤處理代碼
  3. 現有的基於SFI的測試方法(效果很好,但是他們僅執行上下文無關的故障注入,使測試無法深入的進行

下圖解釋了現有基於SFI測試方法的侷限性。

在主函數中,分配了一個x和y,然後調用了函數FuncA和FuncB,FuncA和FuncB都調用FuncP,但是FuncB在調用FuncP之前釋放了傳遞過來的參數。在FuncP中,通過調用malloc分配對象z,如果malloc調用失敗,則釋放傳遞過來的參數,並調用exit退出程序。

如果使用上下文無關的SFI技術,將故障注入到FuncP中的malloc中,使該函數始終無法調用成功。則在執行FuncA時,程序將始終退出,而不會發現任何錯誤。
在這裏插入圖片描述
如果使用上下文相關的SFI技術,並且僅在FuncB調用FuncP時纔將故障注入到FuncP中的malloc中,則可以在運行時觸發對象的雙重釋放錯誤。

在本文中,爲了有效地檢測錯誤處理代碼中的bug,設計了一種基於上下文敏感的SFI的模糊測試方法。該方法將執行上下文納入考慮範圍,以有效地指導SFI以最大程度地發現bug。它包括六個步驟:
1)使用靜態分析技術識別可能存在錯誤的位置
2)收集執行error site的上下文調用和代碼覆蓋率的運行時信息
3)根據運行時的信息創建已執行error site的錯誤序列
4)對創建的錯誤序列進行突變生成新的錯誤序列
5)將變異後的錯誤序列注入到程序中
6)收集運行時信息,創建新的錯誤序列,然後再次對這些錯誤序列進行變異,從而構成了模糊循環。
在這裏插入圖片描述
根據作者設計的基於上下文敏感的SFI的模糊測試方法,提出了一個新的模糊框架FIFUZZ。在編譯時,爲了減少識別error site的人工工作,FIFUZZ對測試程序的源代碼進行靜態分析,以識別可能的error site。然後,FIFUZZ在運行時測試中使用基於上下文敏感的基於SFI的模糊方法。另外,爲了與程序輸入的傳統模糊測試處理兼容,FIFUZZ通過分析測試程序的運行時信息,將錯誤序列和程序輸入一起突變。

3、FIFUZZ Framework

3.1 FIFUZZ架構

FIFUZZ是使用Clang實現的,對測試程序的LLVM字節碼進行代碼分析和代碼檢測。主要包括6部分:

  1. error site提取器。它對測試程序的源代碼執行靜態分析,識別可能的error site。
  2. 程序生成器。它對程序代碼進行代碼檢測,包括識別出的error site,函數調用,函數入口和出口,代碼分支等,生成可執行的經過測試的程序。
  3. 運行時監視器。它使用生成的輸入來運行測試程序,收集測試程序的運行時信息,並根據生成的錯誤序列進行故障注入。
  4. 錯誤序列生成器。它根據收集的運行時信息創建錯誤序列,並對錯誤序列進行突變以生成新的錯誤序列。
  5. 輸入生成器。根據收集的運行時信息,它執行傳統的模糊處理以變異並生成新的輸入。
  6. 錯誤檢查器。他們檢查收集的運行時信息以檢測錯誤並生成錯誤報告。
    在這裏插入圖片描述

FIFUZZ主要由兩階段組成,分別是Compile-Time Analysis和Runtime Fuzzing

3.2 Compile-Time Analysis

在這個階段,FIFUZZ主要做兩件事情,分別是error site提取和代碼檢測

error site提取:

error site的提取着重於提取特定的函數,因爲作者根據調查發現,大多數error site都與檢查函數返回值有關。關於error site的提取主要包括三個步驟:

S1:確定候選的error site。在許多情況下,函數調用會返回空指針或負整數表示調用失敗。因此,在以下情況下,我們將函數調用標識爲候選error site:1)函數返回了指針或整數; 2)判斷返回值是否是NULL或0

int [*] getData1() {
    ...
} 
getData1() // 候選error site
typedef struct {
    ...
}A;
A getStu() {
    ...
}
if (getStu() == null || getStu() == 0) {
    
}

getStu() // 候選error site
S2:選擇庫函數。在大多數情況下,被測試程序中自定義的函數會執行失敗,因爲它調用了特定的庫函數(例如對malloc進行SFI注入,那麼所有使用了malloc的自定義函數都會執行失敗)。如果將自定義函數和其調用的庫函數都用於SFI,則可能會注入重複的故障。爲了避免重複,我們從所有識別的函數調用中選擇了那些被調用函數爲庫函數的函數。

void funcA() {
    char *p = (char*)malloc(10 * sizeof(char));
    ...
}
// 只對malloc進行SFI,不對funcA進行SFI

S3:進行統計分析。在某些情況下,函數可能會失敗並觸發錯誤處理,但是if語句沒有對該函數的返回值進行檢查。
爲了處理這種情況,使用了一種統計方法來提取error site。

代碼檢測:

代碼檢測主要用於兩個目的:收集有關error site的運行時信息和注入故障。爲了收集有關每個error site的運行時調用上下文的信息,程序生成器會在對被測試程序代碼中定義的函數進行調用之前和調用之後,函數的入口和出口處對代碼進行檢測。
在這裏插入圖片描述
此外,爲了監視error site的執行並將錯誤注入其中,程序生成器會在每個error site之前檢測代碼。在程序執行期間,將收集此error site的運行時調用上下文及其位置以創建錯誤點。上圖顯示了C代碼中的檢測代碼示例。注意代碼檢測實際上是在LLVM字節碼上執行的。

3.3 Runtime Fuzzing

Runtime Fuzzing使用傳統的模糊處理過程生成的程序輸入來執行測試的程序,並使用基於SFI的模糊方法生成的錯誤序列將故障注入程序中。它還收集有關已執行的錯誤點,代碼分支等的運行時信息。錯誤序列生成器根據收集的運行時信息創建錯誤序列,並進行突變生成新的錯誤序列。輸入生成器執行覆蓋率指導的突變以生成新輸入。然後,FIFUZZ將這些生成的錯誤序列和輸入組合在一起。

4、Evaluation

4.1 和上下文無關進行比較

在這裏插入圖片描述
從上圖可以看出基於上下文的SFI生成的有用的錯誤序列更多,測試出來的錯誤也更多。alert -> 觸發警報,同時觸發的警報也更多。

4.2 與現有模糊測試工具的比較

選擇了四種流行的開源模糊測試工具進行比較,包括AFL,AFLFast,AFLSmart和FairFuzz。同時,爲了驗證FIFUZZ的通用性,在舊版本2.26(2016年1月發佈)的Binutils工具集中中選擇了5個常見程序(nm,objdump,size,ar,readelf)作爲測試程序。我們使用FIFUZZ和四個模糊測試工具對每個程序進行模糊測試,每個模糊測試的時間限制爲24小時。
在這裏插入圖片描述
圖13是模糊測試期間每個測試程序的代碼覆蓋分支。與AFL和AFLFast相比,FIFUZZ通過覆蓋更多的錯誤處理代碼來覆蓋所有經過測試的程序中的更多代碼分支。與AFLSmart和FairFuzz相比,FIFUZZ在nm,大小和ar上覆蓋了更多的代碼分支,但是在objdump和readelf中覆蓋了更少的代碼分支。主要原因是FIFUZZ中程序輸入的模糊處理是通過引用AFL來實現的,而AFLSmart和FairFuzz使用一些技術來改進AFU中模糊程序輸入的突變和種子選擇。出於這個原因,儘管AFLSmart和FairFuzz仍然錯過了FIFUZZ覆蓋的許多錯誤處理代碼,但它們可以覆蓋與輸入有關的不經常執行的代碼。

表9顯示了錯誤檢測的結果。首先,AFLSmart,FairFuzz和FIFUZZ還發現了AFL和AFLFast發現的兩個錯誤。其次,AFLSmart和FairFuzz分別找到了AFL,AFLFast和FIFUZZ遺漏的一個bug。 AFLSmart發現的一個額外錯誤與FairFuzz發現的不同,因爲它們以不同的方式改善了程序輸入的變異和種子選擇。最終,FIFUZZ找到了14個錯誤,其中12個與錯誤處理代碼有關的錯誤被AFL,AFLFast,AFLSmart和FairFuzz遺漏了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章