核心中的控制流程完整性

控制流程完整性 (CFI) 是一種安全機制,可禁止變更已編譯二進位檔的原始控制流程圖,大幅提高這類攻擊的難度。

從 Android 9 開始,您可以在核心中啟用 CFI。

Linux 核心有兩種不同的 CFI 實作方式:

  • 適用於 Linux 6.0 以下版本,Clang CFI 依賴 Clang LTO
  • 適用於 Linux 6.1 以上版本,Clang KCFI

Clang CFI 必須使用連結時間最佳化 (LTO) 編譯。LTO 會保留物件檔案的 LLVM 中間碼表示法,直到連結時間為止,讓編譯器能更妥善地判斷可執行的最佳化作業。在 Android 測試中,LTO 和 CFI 的組合對程式碼大小和效能造成的負擔微乎其微。不過,啟用 LTO 會大幅增加核心建構時間。

Clang KCFI 不需要 LTO,因此較新的 Android 核心可享有 CFI 的優點,且不會產生 LTO 的建構時間負擔。

導入作業

CFI 由 CONFIG_CFI_CLANG 選項控制,可啟用 Clang CFI 或 Clang KCFI。

如要進一步瞭解 CFI 和其他轉送控制項檢查的處理方式,請參閱 LLVM 設計文件。在該處,KCFI 稱為 -fsanitize=kcfi

疑難排解

啟用後,請解決驅動程式可能存在的任何類型不符錯誤。透過不相容的函式指標進行間接函式呼叫時,會觸發 CFI。偵測到 CFI 失敗時,核心會列印警告,其中包含呼叫的函式和導致失敗的堆疊追蹤。如要修正這個問題,請確保函式指標一律與所呼叫的函式類型相同。

如要協助偵錯 CFI 失敗情形,請啟用 CONFIG_CFI_PERMISSIVE,這會列印警告訊息,而不是導致核心錯誤。正式環境不得使用寬鬆模式。

驗證

目前沒有專為 CFI 設計的 CTS 測試。請務必確認 CTS 測試在啟用和未啟用 CFI 的情況下都能通過,以驗證 CFI 不會影響裝置。