RFC-0117 - 元件模糊架構

RFC-0117:元件模糊架構
狀態已接受
區域
  • 測試
說明

融合 Fuchsia 原生的跨程序模糊架構。

問題
變更
作者
審查人員
提交日期 (年/月)2021-05-24
審查日期 (年/月)2021-07-28

摘要

「引導式模糊化」可以有效減少平台中的錯誤,提升信心,但目前還沒有適用於 Fuchsia 元件拓撲的程序邊界進行模糊處理的架構。本文件提議針對這類架構的設計,可在各個程序及測試領域內共用涵蓋範圍測試輸入內容,讓元件能在最典型的設定中修復。

提振精神

計畫測試可用來顯示錯誤,但切勿顯示錯誤!

--Edsger W. Dijkstra

引導式模糊化程序是在意見回饋循環中,使用產生的資料測試軟體的程序:

  1. 模糊工具會產生一些「測試輸入」資料,並使用這些資料測試目標軟體。
  2. 如果測試結果失敗,模糊工具會記錄輸入和結束。
  3. 目標軟體會產生由模糊工具收集的意見回饋
  4. 模糊工具會使用該回饋內容產生其他測試輸入內容,並重複執行。

引導式模糊功能對於找出與專案需求無關的軟體錯誤非常有用 (因此通常未經測試)。也可能藉由自動化測試涵蓋率,提高系統對系統具有安全性正確性和/或穩定性考量的部分信心。

您可以使用以下分類來說明引導式模糊架構:
模糊分類

  • 引擎:適用於任何目標的意見回饋循環。
    • Corpus 管理:維護一組模糊輸入 (語料庫)。記錄新輸入內容並修改現有內容,例如合併。
      • 種子語料是一組手動建立的初始輸入。
      • 使用中語料是一組持續更新的產生的輸入內容組合。
    • 調節器:一組「異動策略」,以及用來從語料庫建立新輸入的確定性偽隨機性來源。
    • 意見回饋分析:根據意見回饋處理輸入內容。
    • 管理介面:與使用者進行互動,藉此協調工作流程:
      • 透過特定輸入執行目標,例如執行一次模糊跑步
      • 對目標進行模糊化,也就是執行一連串的模糊執行。
      • 分析或操控指定語料庫。
      • 回應偵測到的錯誤,以及/或處理造成錯誤的構件。
  • 目標:要模糊處理的特定目標領域。
    • 輸入處理:將單次執行作業的模糊化輸入內容對應至測試中的程式碼,例如透過特定函式、I/O 管道等。
    • 收集意見回饋:觀察輸入內容所產生的行為。可能會收集硬體或軟體追蹤記錄、程式碼涵蓋率資料、時間等。
    • 錯誤偵測:判斷輸入內容何時導致錯誤。收集並記錄測試成果,例如輸入、記錄檔、反向追蹤記錄等。

其中某些層面可能需要 OS 和/或其工具鍊的特定支援,例如意見回饋收集和錯誤偵測。目前在 Fuchsia 上,最受完整支援的模糊架構是 libFuzzer,這個架構是透過預先建立的 clang 工具鍊做為編譯器執行階段提供。已將支援新增至用於收集程式碼涵蓋率意見回饋的 sanitizer_common 執行階段,以及 libFuzzer 本身來偵測例外狀況。除了一組 GN 範本主機工具,開發人員還能為 Fuchsia 上的程式庫快速開發漏洞攻擊。

然而在 Fuchsia 上,軟體的基本可執行單位是元件,而非程式庫。使用現有的引導式模糊元件執行模糊元件的操作相當麻煩,因為其回饋的精細程度過於狹窄 (例如單一程序中的 libFuzzer) 或過於籠統 (例如對 qemu 例項使用 TriforceAFL)。

Fuchsia 中適合用來設計模糊元件的架構具有以下特點:

  • 與現有的持續模糊基礎架構整合,例如 ClusterFuzz
  • 模組化方法可運用其他模糊架構的其他部分,例如異動策略。
  • 高效能的跨程序程式碼涵蓋率機制。
  • 整合現有的 Fuchsia 工作流程,例如 ffx
  • 可隔離受測試元件的密封環境,和/或提供其依附元件的模擬元件。
  • 目標元件未經修改的來源。
  • 分析執行作業及偵測錯誤的完善彈性方法。
  • 與 Fuchsia 中其他測試方式類似的開發人員經驗談。

設計

這項設計會嘗試:

  • 愛上富奇亞的習慣。
  • 重複使用現有的導入方式。

整體設計會利用測試執行元件工具架構,並新增以下項目:

  • 用於驅動模糊程序的 fuzzer_engine
  • ffx 外掛程式和模糊管理員可與其互動和管理模糊化工具。
  • 用於將 fuzzer_engine 連線至模糊管理員的 fuzz_test_runner


元件模糊架構設計

本文件的本節大致是根據控制流程進行組織,也就是從以人類或機器人為開頭,希望執行模糊工作,並將目標領域發揮到模糊化。讀者應留意,部分章節會詳細說明後續章節所述的概念。

ffx fuzz 主機工具

使用者 (真人和機器人) 會透過 ffx 外掛程式與架構互動。這個外掛程式將可透過以下方式與 fuzz_manager 服務通訊:

ffx fuzz 的子指令會反映 fx fuzz 的子指令,例如:

  • analyze:回報特定語料庫和/或字典的涵蓋範圍資訊。
  • check:檢查一或多個模糊工具的狀態。
  • coverage:產生測試的涵蓋範圍報表。
  • list:列出目前版本中可用的模糊化函式。
  • repro:重播測試單元,重現模糊測試發現的問題。
  • start:啟動特定的模糊功能。
  • stop:停止特定的模糊工具。
  • update:更新 BUILD.gn 檔案以產生模糊的語料庫。

Fuzz Manager

執行元件提供兩項重要功能:

  • 您可以輕鬆建立複雜但密封的測試領域,並使用可自訂的測試執行者推動測試。
  • 可讓您收集重要診斷資料,例如記錄檔和反向追蹤記錄。

此外,單一模糊執行作業能以元件測試架構的術語自然來表達:程式碼會使用指定的測試輸入內容練習,並根據是否發生錯誤,將程式碼視為通過或失敗。

不過,模糊測試與其他測試形式不同,在比較「持續模糊測試」與「持續測試」時,差異會更加明顯:

  • 測試輸入內容不明。
    • 測試內容因模糊化而產生。
    • ClusterFuzz 等持續模糊基礎架構的基礎架構會有多個模糊化執行個體,且會在模糊化期間「交叉輪詢」的測試輸入內容。
  • Fuzz 測試執行作業已開放。Fuzz 測試實際上絕對不會「通過」,只會失敗或提早停止。
    • 因此,您需要提供隨選狀態,其中包含其他測試通常未提供的詳細資料,例如執行速度、收集的總意見回饋和耗用的記憶體等。
    • 這個狀態必須持續提供給監控模糊工具執行作業的真人或模糊基礎架構機器人。
  • 模糊測試結果比通過/失敗更豐富。
    • 失敗時,輸出必須包含觸發的輸入內容,以及任何相關的記錄檔和回溯追蹤記錄。
    • 提前終止時,輸出可能會包含累積意見回饋和建議的參數 (例如字典),以便日後執行模糊作業。
  • 模糊的領域可用於模糊基礎架構選擇連續執行的不同工作流程,例如「Fuzz for a 一段時間」。如果發現錯誤,請予以清理,否則請合併及壓縮語料庫。以測試套件的形式呈現每個步驟,可大幅從一個步驟中擷取狀態,只在下一個步驟中還原狀態。

擴充測試執行元件工具架構即可解決其中部分問題,例如,該架構可以提供結構化的輸出內容。不過,如果採用這個方法處理所有模糊需求,則會為其他不需要此類測試的測試新增重要功能。因此,設計會新增具有以下特性的新 fuzz_manager

接著測試執行工具架構如下:

  1. 新增 fuzz_test_runner。此執行元件以現有的 elf_test_runner 為基礎,以啟動 fuzzer_engine 並將其傳遞到模糊工具網址。
  2. 修改 test_manager,將 fuchsia.fuzzer.manager.Harness 能力轉送至 fuzz_test_runner。這項能力「不會」轉送至測試,且非模糊工具的密封狀態不會受到影響。
  3. fuzz_test_runner 會建立 fuchsia.fuzzer.Controller 通訊協定的管道配對。這會在 fuzzer_engine 中安裝一端做為啟動控制代碼,並使用 fuchsia.fuzzer.manager.Harness 將另一個傳遞至 fuzz_manager

模糊引擎

fuzzer_engine 是模糊領域的元件。以模糊化分類來說:

  • 實作 fuchsia.fuzzer.Controller 通訊協定以提供管理介面
  • 建立並使用儲存空間能力管理各個語料庫
  • 將語料庫的輸入內容簡化,建立新的測試輸入內容。(例如與 libMutagen 的連結)。
  • Uses 這項 Adapter 能力可以傳送要處理的新輸入
  • Exposesfuchsia.fuzzer.ProcessProxy 能力,用於檢測模糊領域中的遠端程序,可用來提供收集的意見回饋回報錯誤
  • 分析意見回饋

如果模糊程序是輸入不同輸入的一系列測試,其中一種方法就是讓模糊引擎為每個輸入項目將新的測試領域執行個體化,即測試的「執行者」runner連續執行每次模糊作業「執行」runner。這種方法的重大問題是意見回饋分析和異動循環的效能。模糊效果與處理量直接相關,且主要迴圈速度非常快:「變更、處理輸入、收集意見回饋及分析意見回饋」的負擔應該以微秒為單位。

因此,模糊工具引擎會隨附在測試領域本身,如同用於測試複雜拓撲的測試驅動程式本身。事件配對協調的共用 VMO 會用來將測試輸入轉移到模糊目標轉接程式,以及來自檢測遠端程序的意見回饋,盡可能降低延遲時間。

模糊引擎是由 fuzz_test_runner 啟動。這個執行元件與現有 elf_test_runner 非常類似,但有一個重要的新增項目:它會為 fuchsia.fuzzer.Controller 通訊協定建立通道。這會在 fuzzer_engine 中安裝這個配對的其中一端做為啟動控制代碼。使用由 test_manager 轉送的 fuchsia.fuzz.manager.Harness 能力,將另一個傳遞至 fuzz_manager。這樣做可讓 test_manager 只提供 Harness 能力給 fuzz_test_runner 和啟動的模糊化程序,而不是提供給所有測試。

目標轉接程式

模糊目標轉接程式會在模糊分類中執行「輸入處理」角色。會使用上述的共用 VMO 和事件組合,接收模糊引擎產生的測試輸入內容,並將這些輸入內容對應至正在模糊化的目標領域中檢測遠端程序的特定互動。

這類特定互動是由模糊工具作者提供,通常稱為「改寫模糊」。

模糊的作者可以提供自己自訂的模糊目標轉接程式或使用所提供的 Scaffold 之一。

可能的轉接器鷹架範例包括:

  • llvm_fuzzer_adapter:預期作者會實作 LLVM 的模糊目標函式

    • 對於 C/C++,作者會實作:
    extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
    
    • 如果是 Rust,作者會使用 #[fuzz] proc_macro 屬性實作方法。
    • 在 Go 中,作者會實作:
    func Fuzz(s []byte);
    
  • realm_builder_adapter:除了 LLVM 模糊目標函式外,作者也實作了修改所提供 RealmBuilder 的方法。轉接程式為這個函式提供預設建構工具,並使用該結果建構要模糊化的元件領域。作者可以新增其他路徑、功能、模擬等來修改該路徑:

    pub trait FuzzedRealmBuilder {
      fn extend(builder : &mut RealmBuilder);
    }
    
  • libfuzzer_adapter:與 llvm_fuzzer_adapter 類似,但其元件資訊清單會省略模糊引擎引擎、提供 Controller 能力,以及直接與 libFuzzer 的連結。這樣的元件拓撲有明顯不同的元件拓撲,允許在這個架構中使用傳統程式庫的 libFuzzer 模糊功能。

  • honggfuzz-persistent-adapter:預期編寫模糊效果的作者必須實作:

    extern HF_ITER(uint8_t** buf, size_t* len);
    

    目前不支援 honggfuzz 本身,但針對此架構編寫的模糊目標函式仍可與這個架構整合。

請注意,目標轉接程式也可以也應與遠端程式庫連結,並做為檢測的遠端程序,以及檢測目標中的程序。

檢測遠端程序

為了收集意見回饋並偵測錯誤,目標領域中的所有程序都必須使用額外檢測方法 (例如 SanitizerCoverage) 進行建構。如果是內建漏洞的樹狀結構,可以透過工具鍊變化版本套用至 GN 目標的依附元件,flagsdeps。必要的標記 (例如 -fsanitize-coverage=inline-8bit-counters) 將會記錄,以允許樹狀結構外編譯。

此外,程序也需要使用 fuchsia.fuzzer.ProcessProxy 用戶端實作。與上述相同的工具鍊變化版本,可自動新增依附元件,藉此連結遠端程式庫的樹狀結構內結構模糊工具程序。

遠端程式庫會根據模糊分類提供:

  • 透過回呼收集意見回饋,例如 __sanitizer_cov_inline_8bit_counters_init
  • fuzzer_engineProcessProxy 的早期啟動連線。
  • 偵測錯誤的背景執行緒,例如監控例外狀況和記憶體用量等。

樹狀結構外模糊工具可以提供自己的用戶端實作。將 fuchsia.fuzzer.ProcessProxy FIDL 介面和遠端程式庫實作新增至 SDK,可更輕鬆編寫樹狀結構外模糊工具。

最後,必要的編譯時間修改作業只會在 LLVM IR 上進行轉換。所有其他修改作業都只有連結時間。讓服務供應商在不需要原始碼的情況下,為願意為元件提供 LLVM 位元碼的 SDK 消費者提供「模糊化服務」服務。

元件拓撲

將上述所有資訊整合在一起,模糊的元件拓撲包括:

  • core:系統根元件。
  • fuzz_manager:模糊功能與主機工具在根領域中的橋接器。
  • test_manager:如測試執行工具架構所示。
  • target_fuzzer:模糊的領域進入點。
  • fuzzer_engine:無目標模糊化驅動程式庫。
  • target_adapter:包含使用者提供的輸入處理程式碼的目標特定元件。
  • instrumented_target:元件遭到模糊化。

adaptertarget 元件可能有額外的子項,例如模擬和目標領域遭到模糊化。

上述各點的互動方式如下:
模糊架構拓撲

FIDL 介面

這個架構新增兩個 FIDL 程式庫:一個用於與 fuzz_manager 互動,另一個用於與模糊工具本身互動。

fuchsia.fuzzer.manager

fuchsia.fuzzer.manager 定義的類型包括:

  • LaunchError:可延伸的 enum 列出與尋找及啟動模糊工具相關的錯誤。

fuchsia.fuzzer.manager 定義的通訊協定包括:

  • fuchsia.fuzzer.manager.Coordinator:由 fuzz_manager 透過 ffx 向使用者提供。包含啟動模糊工具及連結 fuchsia.fuzzer.Controller 的方法,以及停止模糊處理的方法。
  • fuchsia.fuzzer.manager.Harness:由 fuzz_manager 提供,透過 coretest_manager 靜態轉送給 fuzz_test_runner。執行器會使用這個通訊協定,將管道的結尾傳遞至可用於 fuchsia.fuzzer.Controller 通訊協定的管理員。

fuchsia.fuzzer

fuchsia.fuzzer 定義的類型包括:

  • Options:可延伸的 table,具有設定執行、錯誤偵測等參數的參數。
  • Feedback:表示目標意見回饋的彈性 union,例如程式碼涵蓋率、追蹤記錄、時間等。
  • Status:可擴充的 table,搭配各種模糊指標,例如總涵蓋範圍、速度等。
  • FuzzerError:可擴充的 enum 列出錯誤類別,例如 ClusterFuzz 識別的錯誤類別。

fuchsia.fuzzer 定義的通訊協定包括:

  • fuchsia.fuzzer.Controller:由 fuzzer_engine 提供,並透過 fuzz_test_runner 傳遞至 fuzz_manager。由 fuzz_manager 透過 Proxy 進行 Proxy 處理。包括將輸入內容轉移至模糊化函式或構件的方法,以及在模糊化 (例如輸入最小化、語料庫合併和一般模糊化) 上執行工作流程。
  • fuchsia.fuzzer.CorpusReaderfuchsia.fuzzer.Controller 的要求。用於取得特定種子或即時語料庫的輸入內容。
  • fuchsia.fuzzer.CorpusWriterfuchsia.fuzzer.Controller 的要求。用於將輸入內容新增至特定種子或即時語料庫。
  • fuchsia.fuzzer.Adapter:由開發人員提供的 target_adapter 提供給 fuzzer_engine。包含註冊協調事件配對的方法,以及用於傳送測試輸入內容的共用 VMO。
  • fuchsia.fuzzer.ProcessProxy:由 fuzzer_engine 提供給模糊領域中各項檢測程序。包括註冊協調事件配對的方法,以及註冊用於提供意見回饋的共用 VMO。

建構公用程式

這個架構為開發人員提供 fuchsia_fuzzer_package GN 範本。如此一來,他們就能:

  • 自動加入 fuzzer_engine。
  • 產生可透過工具使用的中繼資料 (例如種子語料庫的位置)。
  • 測試一節所述,選取非模糊工具鍊變化版本時,應建構整合測試而非模糊工具。
  • 針對接受相關整合測試的測試元件,重複使用建構規則。

這個架構也包含元件資訊清單資料分割,包含模糊工具所需的常用元素,例如 fuzzer_engine 及其功能、fuzz_test_runner 等。模糊工具的元件資訊清單包含下列內容:

  • 預設的模糊資料分割。
  • 目標轉接程式元件的網址。
  • 要模糊元件的資訊清單網址。通常可透過相關的整合測試重複使用。

這些建構公用程式旨在提供與整合測試開發體驗相似的模糊開發體驗。比較:
測試和模糊測試的開發程序

實作

實作計畫非常簡單:透過一系列變更中的個別類別開發及單元測試,然後組合從 libFuzzer 衍生的整合測試,如「測試」一節所述。

語言

fuzzer_engineremote_library 是在 C++ 中實作,協助其慣用語:

  • fuzzer_engineremote_library 都必須與其他 CBI 整合,例如 libMutagenSanitizerCoverage 等。
  • 大部分的 remote_library 功能會在「main」之前和「exit」之後發生,即建構和/或載入 LLVM 模組、執行 atexit 處理常式,或引發嚴重例外狀況時。因此,該架構需要明確控制 ELF 執行檔生命週期的細微細節。

其他項目 (例如 realm_builder_adapter) 則是以 Rust 編寫。

資料移轉通訊協定

在某些情況下,使用者必須能夠提供或擷取任意數量的資料,包括:

  • 提供要執行、清理或最小化的特定測試輸入內容。
  • 在開發人員主機或多個 ClusterFuzz 執行個體之間同步處理模糊語料庫。
  • 擷取觸發錯誤的測試輸入內容。

為了將維護負擔降到最低,建議您使用 overnet 轉移這項資料。但是,在 Zircon 管道上,任何單次傳輸可能會超過單一 FIDL 訊息的大小。而是 Controller 通訊協定包含數種方法,這些方法會提供 zx_socket 物件,讓模糊引擎使用這些物件向 VMO 和/或儲存在本機的檔案之間串流資料。

系統會使用最少的通訊協定串流資料,以便讀取或寫入已命名的位元組序列。通訊協定並「不是」FIDL,因為傳送的資料可能會超過 FIDL 訊息的長度上限。仍然,已命名的位元組序列在概念上與下列 FIDL 結構相等:

struct NamedByteSequence {
  uint32 name_length;
  uint32 size;
  bytes:name_length name;
  bytes:size data;
};

解開堆疊

目前,libFuzzer 使用 LLVM 的解開器,並假設是透過觸發信號的執行緒上執行的 POSIX 信號處理常式呼叫該資料集。對如此,Fuchsia 需要採取複雜的方法來處理例外狀況,包括修改已停止運作的執行緒的堆疊,以及插入回溯追蹤的 Trampoline,以「收回」解開器中的執行緒。

如果 libFuzzer 未處理錯誤,則不必執行這些步驟。而是以最方便且有效的方式處理不同類型的錯誤,例如:

  • 例外狀況會由模糊測試引擎處理,而該引擎會從其處理常式建立的模糊測試執行元件,接收其例外狀況管道。
  • 逾時也會由模糊引擎管理。
  • Sanitizer 回呼和 OOM 是由遠端程式庫處理,並通知模糊引擎。

效能

模糊功能不會在實際工作環境系統上執行,因此不會影響任何運送程式碼的效能。雖然加入模糊工具鍊變化版本對建構 Fuchsia 的效能有些微影響,但這個架構會重複使用現有的變化版本,且應該不會新增任何影響。

同樣地,在未檢測版本上從模糊化產生單元測試的結果與現行做法相同,因此無需為目前的方法增加任何大量的模糊測試費用。

對模糊處理工具本身而言,判斷模糊度品質最重要的指標是每單位時間的涵蓋範圍,您可以透過評估另外兩個指標得出這項結果:

  1. 模糊刷子在固定時間內的總涵蓋率。
  2. 在固定時間內執行的總執行作業總數。

ClusterFuzz 已經針對資訊主頁上的每個模糊功能監控及發布這些指標。

人體工學

人體工學是本設計的重要面向,因為其影響取決於開發人員的採用情形。

這個架構嘗試以幾種方式盡可能簡化模糊作業。可讓開發人員:

  • 目標轉接器一節所述,請以熟悉且彈性的方式編寫模糊工具。
  • 使用現有的 GN 模糊範本系列製作模糊效果。
  • 使用熟悉的工作流程執行模糊工具。ffx fuzz 的用法刻意與 fx fuzz 類似。
  • 取得可做為行動依據的結果。與 ClusterFuzz 錯誤整合後,系統會自動使用符號化的回溯追蹤記錄和重製指示,自動回報錯誤。

回溯相容性

現有的 libFuzzer 模糊處理工具會實作fuzz 目標函式。透過提供 libFuzzer 專用的模糊目標轉接器,這些模糊功能就可以在這個架構中運作,無需修改原始碼。

安全性考量

這個架構不會用於運送產品設定。如果是內建模糊設定的裝置,與裝置之間的通訊會使用 overnetffx 提供的現有驗證和安全通訊功能。

模糊測試的輸出內容可能有安全性考量,例如測試輸入可能會導致遭利用的記憶體損毀。這類疑慮「必須」由模糊運算子 (人工或模糊基礎架構) 處理,方法與任何其他可供利用的錯誤報告相同,例如修正標籤、防止未經授權的揭露行為等。

隱私權注意事項

在考量影響隱私權的因素時,我們不會對模糊運算子處理錯誤輸出的方式做出任何假設。這些輸出內容包含符號化記錄檔、導致出錯的輸入內容、產生的字典和產生的語料庫。由於是獨立且密切監控的隱私權疑慮,我們認為這些記錄已經沒有任何使用者資料。剩餘的輸出全都是直接衍生自測試輸入內容。因此,將模糊的「輸入」保留在使用者資料中,除了使用者資料之外,還要有足夠空間,防止使用者資料遭到模糊化的「輸出內容」

有三種方式將輸入新增至模糊現象的語料庫:

  • 如種子輸入。應檢查原始碼存放區中。違反在原始碼存放區中加入使用者資料的一般限制。
  • 做為即時語料庫的手動添加項目。
    • 這通常會由模糊的基礎架構 (例如 ClusterFuzz) 執行,因為這類架構可透過其他執行個體產生的輸入內容,進行交叉輪詢。在此情況下,其他執行個體將不包含使用者資料,新增的輸入內容也不會包含。
    • 真人操作員也可以透過 ffx 新增輸入內容。以這種方式手動新增輸入內容時,工具會顯示有關使用者資料的警告。
  • 即時語料庫的新增內容。這些輸入內容從現有輸入內容中變化。這些輸入內容是不含使用者資料的行為,因此產生的資料也能產生。部分輸入內容可能會單靠偶然來比對某些使用者資料,例如模糊工具會設法產生有效的使用者名稱。不過,在這種情況下,使用者資料並沒有明顯的關聯。

即使模糊工具不具黏著度 (且非確定性!) 並使用來自測試領域公開來源的資料,資料庫也不會納入任何其他資料。架構不會將這些資料視為測試輸入內容的一部分,也不會儲存這些資料。

最糟的情況是模糊情況,設計為故意非密封,並使用公開功能,將測試領域中的資料「傳出」到可驗證 PII 的其他服務,例如傳回使用者名稱是否有效。如要規避模糊和測試架構,以提升密封度,您需要投入大量心力來規避這個架構。此外,由於外部服務並未檢測,因此這不應比隨機猜測更好。

此外,在實務上,模糊的部分會完全深藏著迷人的意味。這些它們不會在含有使用者資料的產品設定中執行,而只會在開發模糊器和 ClusterFuzz 時在本機執行。

測試

模糊引擎、目標轉接器程式庫和遠端程式庫,都是以一般方式 (例如 GoogleTest#[cfg(test)] 等) 進行單元測試。此外,整合測試會使用預設的 ELF 測試執行元件,根據編譯器-rt 中適用的部分,使用特製範例目標執行一組模糊工作流程。

對於使用架構編寫的模糊工具,架構將採用與 GN 模糊工具範本目前支援的相同的方法:在「未檢測」版本中建構模糊化器時,系統會將引擎替換為僅執行種子語料庫中的每個輸入內容的測試驅動程式庫。這可確保所有模糊功能都能建構和執行,藉此減少「位元旋轉」問題。這也可以做為迴歸測試,特別是在修正模糊化發現的瑕疵時,加入輸入內容來維護種子主體。

說明文件

您需要將模糊說明文件樹狀結構更新為使用新 GN 範本的特定範例。任何其他預定的說明文件異動 (例如程式碼研究室等) 也應反映這個架構。

缺點與替代方案

建議的做法包括:

  • 效能降低的風險,透過實作密切模擬高度最佳化模糊工具區段的效能,藉此降低風險。
  • 維護負擔,因不需要維持不易維持整合 (例如 POSIX 模擬) 而節省的成本抵銷。
  • 耦合風險 (例如「測試執行器架構」) 可能會改變導致此設計在未來中斷的方式,或因為此設計而無法進行。如果日後這個問題成為問題,則可將更多 test_manager 的功能直接整合至 fuzz_manager 即可解決,例如讓後者直接建立獨立的測試領域。

這些缺點的順序並不像已探索的其他替代方法一樣:

僅使用 libFuzzer 程式庫模糊功能。

為 libFuzzer 新增足夠的 Fuchsia 支援,以便在 Fuchsia 上透過此工具建構模糊功能。過去幾年來,他們成功找出了數百個錯誤。

同時,這類程序僅限於以程式庫結構化的單一程序。由於元件是 Fuchsia 上的可執行軟體單位,而且元件會透過 FIDL 廣泛通訊,因此會出現大量且不斷增加的 Fuchsia 程式碼。


傳統 LibFuzzer

處理中的 FIDL 模糊功能。

Chrome 等專案嘗試在單一程序中執行用戶端和伺服器執行緒,藉此解決 RPC 模糊問題。這需要修改用戶端和伺服器,才能在新的非標準設定中執行。這可在服務之間重複使用,但通常較無彈性的元件生命週期和/或各語言繫結重新實作的假設。

更基本上,更難以模糊互動元件的關閉。許多元件都具有簡單的拓撲。如果整個閉路迅速執行或模擬,在複雜性、負擔和效能方面就會難以維持永續性。

此方法已推出適用於 Fuchsia,但至少因為上述限制的其中一部分,尚未廣泛採用。


處理中的 FIDL 模糊作業

單一服務 FIDL 模糊功能。

最初嘗試設計跨程序 FIDL 模糊架構時,系統會將其視為單一用戶端和服務。在此設計中,libFuzzer 與服務建立連結,而用戶端是以簡易 Proxy 的形式維護。透過在用戶端和伺服器之間保留 FIDL 介面,即可讓目標採用較典型的設定,這樣可提供更彈性的服務生命週期,並減少重新實作所需的程式碼。

但是,這無法解決模糊元件關閉的問題,因此對於程序中的 FIDL 模糊功能而言,這項功能的益處有限。


單一服務 FIDL 模糊化

LibFuzzer,支援跨程序模糊功能。

原則上,重複使用程式碼有幾項優於重新實作程式碼的優點:程式碼通常更「成熟」,效能較佳、錯誤較少,並會降低共用的維護成本。基於這些原因,另一個先嘗試擴充 libFuzzer,而非設計並導入新的模糊架構。新的編譯器執行階段 clang_rt.fuzzer-remote.a 會做為上方的遠端程式庫,而 libFuzzer 本身則可做為引擎使用。這兩個編譯器執行階段都使用一對 OS 專屬的 IPC 傳輸程式庫,透過 Proxy 方法呼叫其他程序。

與 libFuzzer 的維護人員合作,一同執行了一系列變更,並且將其發布以供審查。此外,IPC 傳輸程式庫的實作方式同時適用於 Linux 和 Fuchsia。維護人員明確要求 Linux 支援,以便持續測試,且應用程式再次送交審查

  • 在 Linux 上,共用記憶體是以匿名對應檔案的形式 (例如透過 memfd_create) 建立,而信號則是僅透過 Unix 網域通訊端傳遞的訊息。這些通訊端也用於轉移共用記憶體檔案描述元,即透過 sendmsgrecvmsg
  • 在 Fuchsia 上,共用記憶體使用 VMO、事件組合的信號,以及透過 FIDL 訊息交換的方式,實作與本提案的設計類似。

遺憾的是,在延長審查期間,這個做法因技術因素而無法執行,但基於流程因素:經過一段時間後,libFuzzer 維護人員越來越關注讓 libFuzzer 以原本未設計的方式行使該 libFuzzer 的行為,因而需要變更範圍。最後,團隊決定無限期延後提議的變更。


單一服務 FIDL 模糊化

亞利桑那州

LibFuzzer 並不是唯一的模糊架構。有些 (例如 AFL) 是專門設計用來從頭開始交叉程序。不過,有幾個原因會讓 AFL 需要投入更多資金:

  • AFL 假設單一程序需要模糊處理,因此仍遇到閉包問題。
  • AFL 會大量使用特定 Linux 和/或 POSIX 功能,藉此提供意見回饋和錯誤偵測。這些信號包括 POSIX 信號,但更明顯地用於 /proc 檔案系統,而此檔案系統在 Fuchsia 上沒有類比。
  • AFL 會使用修改後的 GCC 檢測程式碼,但該程式碼不屬於 Fuchsia 工具鍊的一部分。

AFLplusplus 是 AFL 的改良分支,由一群安全性研究人員和 CTF 競爭對手維護。它在 FuzzBench 上的效能卓越,並具備模組化 AFL。不過很遺憾,第一個第一個版本已淘汰,第二個版本尚未準備就緒 (或至少還不夠成熟,無法強制修改上述設計)。不過,有幾項部分與本提案的設計一致,日後還有機會整合這些提案以改善架構的涵蓋範圍和/或速度。

附有 qemu 的 AFL

此外,還有幾個結合 AFL 與 qemu 的專案:

  • afl-unicorn 結合 AFL 與 Unicorn,這項專案顯示 qemu 的 CPU 模擬核心,且介面相當簡潔。這可讓您透過 CPU 模擬收集涵蓋率意見回饋,在沒有來源的情況下模糊不透明二進位檔。這個選項不適用於元件架構,原因如下:
    • qemu 的核心 CPU 模擬功能整合相當複雜,Unicorn 決定繼續採 qemu 開發,並鎖定為 2.1.2 版 (與目前第 6.0.0 版 qemu 的版本相比)。預期較近期模擬功能的程式碼可能無法正常運作。
    • 不需要不透明的二進位檔模糊效果。事實上,這項設計只需要檢測目標程式碼,並與遠端程式庫連結;LLVM 位元組程式碼就已足夠完成此操作。
  • TriforceAFL 在完整檢測的 qemu 執行個體上使用 AFL。同樣的,透過收集 qemu 本身的涵蓋率,即使沒有原始碼,也能模糊不透明二進位檔。基於類似下列原因而不適合刊登幼兒園:
    • 同樣,不透明的二進位檔模糊效果也不需要。
    • 此外,由於收集的涵蓋範圍為整個執行個體,由於 TriforceAFL 模糊的情形往往非常吵雜,在許多元件執行時更是如此。通常只適用於模糊受限的設定,例如開機後立即顯示的 USB 驅動程式庫。