Fuchsia 的工具鍊支援使用 LLVM 的 libFuzzer 進行模糊測試。如要針對特定的 介面,您需要實作模糊目標函式, 提供的位元組序列來練習介面。位元組順序稱為 模糊的「input」libFuzzer 會使用模糊目標函式搜尋導致恐慌的輸入內容 或其他錯誤
Fuzz 程式碼範例
在下列每個範例中,假設您想測試程式碼,如下所示:
C/C++
class Parser {
Parser(const std::string &name, uint32_t flags);
virtual ~Parser();
int Parse(const uint8 *buf, size_t len);
};
Rust
struct ToyStruct {
n: u8,
s: String,
}
fn toy_example(input: ToyStruct) -> Result<u8, &'static str>;
簡單的模糊目標函式
針對每種語言,模糊目標函式會使用所提供的位元組來呼叫所需的程式碼。 進行模糊化處理如果模糊介面記錄了參數的限制,您可以拒絕 不符合這些限制條件的輸入值您也可以忽略因失敗而傳回的錯誤 謹慎地處理無效參數,才是正確行為。
C/C++
如果是 C 和 C++,模糊目標函式必須有簽章
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
並傳回 0:
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
Parser parser("", 0);
if (size < 5) {
return 0;
}
parser.Parse(data, size);
return 0;
}
請將這段程式碼放在程式碼模糊不清的來源檔案中,就像單元測試一樣。適用對象
舉例來說,上述程式碼可能位於 parser-fuzztest.cc
中。
Rust
如果是 Rust,建議使用下一節討論的 Arbitrary
特徵。
您也可以建立「手動」模糊目標函式,接近簡易模糊
或指定其他語言的函式。這個函式必須參照位元組切片做為其本身
單一參數,不會傳回任何內容,同時具有 #[fuzz]
屬性:
use fuzz::fuzz;
#[fuzz]
fn toy_example_u8(input: &[u8]) {
if input.len() == 0 {
return
}
let n = input[0];
if let Ok(s) = std::str::from_utf8(input[1:]) {
let _ = toy_example(ToyStruct{n, s: s.to_string(),});
}
}
與單元測試一樣,您可以把這個程式碼放在測試程式碼所在的檔案中。適用對象
舉例來說,上述程式碼可能位於 toy_example/src/lib.rs
中。
支援更多複雜型別
每種語言都有公用程式,可協助您建立更複雜的模糊目標函式:
C/C++
LLVM 提供的 FuzzedDataProvider
類別可協助您
將所提供 data
的部分對應至較複雜的類型。
例如:
#include <fuzzer/FuzzedDataProvider.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
FuzzedDataProvider provider(data, size);
auto flags = provider.ConsumeIntegral<uint32_t>();
auto name = provider.ConsumeRandomLengthString();
Parser parser(name, flags);
auto buf = provider.ConsumeRemainingBytes<uint8_t>();
parser.Parse(buf.data(), buf.size());
return 0;
}
使用這個程式庫有兩項重要優點:
- 首先,您可以更輕鬆地快速撰寫模糊版本。
- 第二,這項服務可以動態分割輸入 有效率地建立新的輸入資料。
其中有個明顯的缺點:
Rust
您可以使用 Arbitrary
特徵建立模糊目標函式,以接收一或多個輸入內容
擷取自 arbitrary
Crate。建議您採取這種做法。
如何編寫能自動轉換任意輸入內容的模糊目標函式:
如有需要,請針對測試程式碼使用的類型實作
Arbitrary
特徵。可能的話 建議的產生方法是自動衍生特徵否則,您可以使用 「手動完成」按照 Crate 的操作說明進行。例如,在
src/lib.rs
中:use arbitrary:Arbitrary; #[derive(Arbitrary)] struct ToyStruct { ... }
建立含有傳遞必要要求的
#[fuzz]
屬性的函式 參數加到要測試的程式碼例如,在
src/lib.rs
中:use fuzz::fuzz; #[fuzz] fn toy_example_arbitrary(input: ToyStruct) { let _ = toy_example(input); }
接下來,您可以使用 GN 和 Ninja 建構新建立的模糊工具。