截至 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 未受到影響 裝置。