Fuzzing LLVM 函式庫與工具¶
簡介¶
LLVM 樹包含許多針對各種元件的 fuzzers。它們建構在 LibFuzzer 之上。如需建置和執行這些 fuzzers,請參閱 設定 LLVM 以建置 Fuzzers。
可用的 Fuzzers¶
clang-fuzzer¶
一個 通用 fuzzer,嘗試將文字輸入編譯為 C++ 程式碼。此 fuzzer 報告的一些錯誤位於 bugzilla 和 OSS Fuzz 的追蹤器 上。
clang-proto-fuzzer¶
一個基於 libprotobuf-mutator 的 fuzzer,它會編譯從描述 C++ 語言子集的 protobuf 類別產生的有效 C++ 程式。
此 fuzzer 接受 ignore_remaining_args=1 之後的 clang 命令列選項。例如,以下命令將使用更高的最佳化級別對 clang 進行模糊測試
% bin/clang-proto-fuzzer <corpus-dir> -ignore_remaining_args=1 -O3
clang-format-fuzzer¶
一個 通用 fuzzer,它會在 C++ 文字片段上執行 clang-format。此 fuzzer 報告的一些錯誤位於 bugzilla 和 OSS Fuzz 的追蹤器 上。
llvm-as-fuzzer¶
一個 通用 fuzzer,嘗試將文字解析為 LLVM 組合語言。此 fuzzer 報告的一些錯誤位於 bugzilla 上。
llvm-dwarfdump-fuzzer¶
一種泛用模糊測試器,會將輸入解譯為物件檔案,並對其執行 llvm-dwarfdump。此模糊測試器回報的部分錯誤列在OSS Fuzz 的追蹤器上
llvm-demangle-fuzzer¶
一種用於各種 LLVM 工具中 Itanium 符號還原器的泛用模糊測試器。我們已經對 __cxa_demangle 進行了詳盡的模糊測試,為何不對 LLVM 的相同函式實作進行模糊測試呢!
llvm-isel-fuzzer¶
一種旨在尋找指令選擇錯誤的結構化 LLVM IR 模糊測試器。
此模糊測試器接受 ignore_remaining_args=1 之後的旗標。這些旗標與 llc 的旗標相符,並且需要指定三元組。例如,以下命令將使用 全域指令選擇 對 AArch64 進行模糊測試
% bin/llvm-isel-fuzzer <corpus-dir> -ignore_remaining_args=1 -mtriple aarch64 -global-isel -O0
某些旗標也可以在二進制檔名中指定,以便支援 OSS Fuzz,因為 OSS Fuzz 在處理必要參數時會遇到問題。為此,您可以將 llvm-isel-fuzzer
複製或移動到 llvm-isel-fuzzer--x-y-z
,使用「–」將選項與二進制檔名分隔。有效的選項包括架構名稱(aarch64
、x86_64
)、最佳化級別(O0
、O2
)或特定關鍵字,例如用於啟用全域指令選擇的 gisel
。在此模式下,可以使用以下方式執行相同的範例
% bin/llvm-isel-fuzzer--aarch64-O0-gisel <corpus-dir>
llvm-opt-fuzzer¶
一種旨在尋找最佳化過程錯誤的結構化 LLVM IR 模糊測試器。
它會接收最佳化流程,並針對每個模糊測試器輸入執行該流程。
此模糊測試器的介面幾乎直接反映了 llvm-isel-fuzzer
。 mtriple
和 passes
參數都是必需的。過程的指定格式適用於新的過程管理器。您可以在 PassBuilder::parsePassPipeline
的 doxygen 中找到有關此格式的一些說明。
% bin/llvm-opt-fuzzer <corpus-dir> -ignore_remaining_args=1 -mtriple x86_64 -passes instcombine
與 llvm-isel-fuzzer
類似,某些預定義配置中的參數可能會直接嵌入到二進制檔名中
% bin/llvm-opt-fuzzer--x86_64-instcombine <corpus-dir>
llvm-mc-assemble-fuzzer¶
一種泛用模糊測試器,會將輸入視為目標特定組譯碼,藉此對 MC 層的組譯器進行模糊測試。
請注意,此模糊測試器的命令列介面並不尋常,無法與 libFuzzer 的所有功能完全相容。模糊測試器參數必須在 --fuzzer-args
之後傳遞,並且任何 llc
旗標都必須使用兩個破折號。例如,若要對 AArch64 組譯器進行模糊測試,您可以使用以下命令
llvm-mc-fuzzer --triple=aarch64-linux-gnu --fuzzer-args -max_len=4
此機制未來可能會有所變更。
llvm-mc-disassemble-fuzzer¶
一種 通用模糊測試器,它將輸入視為已組合的二進制數據來對 MC 層的反組譯器進行模糊測試。
請注意,此模糊測試器具有一個不尋常的命令行界面,它與 libFuzzer 的所有功能並不完全兼容。有關詳細信息,請參閱上面關於 llvm-mc-assemble-fuzzer
的說明。
lldb-target-fuzzer¶
一種 通用模糊測試器,它將輸入解釋為目標文件,並使用它們在 lldb 中創建目標。
突變器和輸入生成器¶
模糊目標的輸入是通過對 語料庫 進行隨機突變生成的。LLVM 中的模糊測試器可能想要使用幾種類型的突變。
通用隨機模糊測試¶
最基本的輸入突變形式是使用 LibFuzzer 的內建突變器。這些突變器只是將輸入語料庫視為一袋比特,並進行隨機突變。這種類型的模糊測試器適用於對程序的表層進行壓力測試,並且擅長測試詞法分析器、解析器或二進制協議之類的東西。
一些使用這種類型突變器的樹內模糊測試器是 clang-fuzzer、clang-format-fuzzer、llvm-as-fuzzer、llvm-dwarfdump-fuzzer、llvm-mc-assemble-fuzzer 和 llvm-mc-disassemble-fuzzer。
使用 libprotobuf-mutator
進行結構化模糊測試¶
我們可以使用 libprotobuf-mutator 來執行結構化模糊測試並對程序的更深層進行壓力測試。這是通過定義一個 protobuf 類來實現的,該類將任意數據轉換為結構上有趣的輸入。具體來說,我們使用它來處理 C++ 語言的一個子集,並執行產生有效的 C++ 程序的突變,以便 exercised 比解析器錯誤處理更有趣的 clang 部分。
要構建這種類型的模糊測試器,您需要安裝 protobuf 及其依賴項,並且在使用 CMake 配置構建時需要指定一些額外的標誌。例如,通過將 -DCLANG_ENABLE_PROTO_FUZZER=ON
添加到 配置 LLVM 以構建模糊測試器 中描述的標誌中,可以啟用 clang-proto-fuzzer。
今天唯一使用 libprotobuf-mutator
的樹內模糊測試器是 clang-proto-fuzzer。
LLVM IR 的結構化模糊測試¶
我們也針對以 LLVM IR 作為輸入的模糊測試器使用更直接的結構化模糊測試形式。 這是透過 FuzzMutate
函式庫來達成,該函式庫曾在 2017 年 EuroLLVM 會議中被討論過。
FuzzMutate
函式庫用於在 llvm-isel-fuzzer 中對後端進行結構化模糊測試。
建置與執行¶
設定 LLVM 以建置模糊測試器¶
只要您在啟用 sanitizer 覆蓋率的情況下建置 LLVM,預設情況下就會建置模糊測試器並將其連結至 libFuzzer。您通常也會啟用至少一個 sanitizer 以更快地找到錯誤。建置模糊測試器的最常見方法是在 CMake 呼叫中新增以下兩個旗標:-DLLVM_USE_SANITIZER=Address -DLLVM_USE_SANITIZE_COVERAGE=On
。
備註
如果您在使用 sanitizer 建置時在 LLVM 樹狀結構中勾選了 compiler-rt
,則需要指定 -DLLVM_BUILD_RUNTIME=Off
以避免在啟用 sanitizer 的情況下建置 sanitizer 本身。
備註
如果您使用 BFD ld 進行建置,則可能會遇到問題,這是許多 Unix 系統上的預設連結器。這些問題正在 https://llvm.dev.org.tw/PR34636 中追蹤。
持續執行與尋找錯誤¶
過去有一個公共建置機器人持續執行 LLVM 模糊測試器,雖然它確實發現了一些問題,但它並沒有很好的方法以可操作的方式報告問題。因此,我們正朝著更多地使用 OSS Fuzz 的方向發展。
您可以瀏覽 LLVM 專案問題清單,查看 OSS Fuzz 上的 LLVM 發現的錯誤。這些錯誤也會郵寄到 llvm-bugs 郵件清單。
用於編寫模糊測試器的工具¶
LLVM 中有一些可用於編寫模糊測試器的工具。
include/llvm/FuzzMutate/FuzzerCLI.h
中提供了一些用於處理命令列介面的輔助函式,包括以一致的方式解析命令列選項以及實作獨立主函式的函式,以便在未針對 libFuzzer 建置時建置和測試您的模糊測試器。
還有一些針對模糊測試器的 CMake 設定的處理,您應該使用 add_llvm_fuzzer
來設定模糊測試器目標。此函式的運作方式類似於 add_llvm_tool
等函式,但它們會在適當的時候處理與 LibFuzzer 的連結,並且可以傳遞 DUMMY_MAIN
參數以啟用獨立測試。