控制流程完整性

截至 2016 年,Android 上的所有漏洞中,約有 86% 是記憶體安全 相關內容。大部分弱點都是由改變常態的攻擊者發動 控制應用程式流程,以使用 針對遭利用的應用程式 取得所有權限 控制流程 完整性 (CFI) 是一種安全機制,可禁止 已編譯二進位檔的原始控制流程圖 執行這類攻擊

在 Android 8.1 中,我們允許了 LLVM 在媒體堆疊中實作 CFI。於 Android 9 支援在更多元件和核心中啟用 CFI。系統 CFI 為 但您必須啟用核心 CFI。

LLVM 的 CFI 需要編譯 連結時間最佳化 (LTO)。LTO 會保留物件檔案的 LLVM 位元率表示法, 連結時間,讓編譯器更能掌握哪些最佳化項目 可以執行啟用 LTO 可縮減最終二進位檔的大小,並改善 但會增加編譯時間在 Android 上進行測試時 的 LTO 和 CFI 會對程式碼大小和效能造成無謂的負擔。風格 但的情況

有關 CFI 的技術細節以及其他前向控制檢查的部署方式 請參閱 LLVM 設計 說明文件

範例和來源

CFI 是由編譯器提供,並於測試期間將檢測作業新增至二進位檔 也就是編譯時間我們支援 Clang 工具鍊和 Android 建構系統中的 CFI 。

根據預設,Arm64 裝置會啟用 CFI /platform/build/target/product/cfi-common.mk。 而且可在一組媒體元件中直接啟用makefiles/藍圖 檔案 (例如 /platform/frameworks/av/media/libmedia/Android.bp) 和 /platform/frameworks/av/cmds/stagefright/Android.mk

實作系統 CFI

如果您使用 Clang 和 Android 建構系統,系統預設會啟用 CFI。 CFI 會保護 Android 使用者的安全,因此請勿將其停用。

事實上,我們強烈建議為其他元件啟用 CFI。 應考慮使用特殊權限的原生程式碼,或用於處理流程的原生程式碼 不受信任的使用者輸入內容如果您使用 clang 和 Android 建構系統, 只要在 makefile 中加入幾行程式碼,就能在新元件中啟用 CFI 藍圖檔案。

支援 makefiles 中的 CFI

如要在 make 檔案 (例如 /platform/frameworks/av/cmds/stagefright/Android.mk) 中啟用 CFI, 新增:

LOCAL_SANITIZE := cfi
# Optional features
LOCAL_SANITIZE_DIAG := cfi
LOCAL_SANITIZE_BLACKLIST := cfi_blacklist.txt

  • LOCAL_SANITIZE 會在 建構應用程式
  • LOCAL_SANITIZE_DIAG開啟 CFI 的診斷模式。 診斷模式會在 Logcat 中顯示額外的偵錯資訊, 這有助於開發及測試版本。廠牌 不過,請務必移除正式版的診斷模式。
  • LOCAL_SANITIZE_BLACKLIST 可讓元件選擇性地 停用個別函式或來源檔案的 CFI 檢測功能。個人中心 使用黑名單是最後手段,修正 否則可能會存在詳情請參閱 停用 CFI

藍圖檔案中支援 CFI

如要在藍圖檔案 (例如 /platform/frameworks/av/media/libmedia/Android.bp) 中啟用 CFI, 新增:

   sanitize: {
        cfi: true,
        diag: {
            cfi: true,
        },
        blacklist: "cfi_blacklist.txt",
    },

疑難排解

如要在新元件中啟用 CFI,可能會遇到一些問題 函式類型不符錯誤組合代碼類型不符 錯誤

發生函式類型不符錯誤,因為 CFI 會將間接呼叫限制為 跳至與 呼叫。CFI 會限制虛擬和非虛擬成員的函式呼叫只能跳躍 屬於物件靜態類型的衍生類別 撥打電話。也就是說,如果您的程式碼違反上述任一 CFI 新增的檢測會取消。舉例來說, 堆疊追蹤顯示 SIGABRT, logcat 包含控制流程的一行 以正確方式找出不相符的項目

如要修正這個問題,請確認所呼叫函式的類型與 靜態宣告以下是兩個 CL 範例:

另一個可能的問題是嘗試在含有間接程式碼的程式碼中啟用 CFI 呼叫組合。由於沒有輸入組合程式碼,因此產生的型別 不相符。

如要修正這個問題,請為每個組合呼叫建立原生程式碼包裝函式,並給予 包裝函式會與呼叫輪詢程式相同的函式簽章。包裝函式可以 即可直接呼叫組合程式碼由於直接分支並非 CFI (憑證無法在執行階段中重新連線,因此不會造成安全性風險)。 這麼做即可修正問題。

如果組合函式過多且無法全部修正,您可以 同時將所有包含對組語的間接呼叫的函式列入黑名單。這是 因為會停用 CFI 檢查這些函式,因此 攻擊面

停用 CFI

系統未觀察到任何效能負擔,因此你應該不需要停用 CFI。不過,如果這類操作會影響使用者,您也可以選擇停用 CFI 提供清理程式黑名單檔案,以便取得個別函式或來源檔案 在編譯期間執行黑名單會指示編譯器停用 CFI 檢測。

Android 建構系統為個別元件的黑名單提供支援 ( 用於選擇不會接收 CFI 的來源檔案或個別函式 檢測方法)。如要進一步瞭解 黑名單檔案,請參閱上游 Clang 說明文件

驗證

目前我們未提供 CFI 專用的 CTS 測試。相反地 無論是否啟用 CFI,都通過 CTS 測試,確認 CFI 未受到影響 裝置。