Scudo 是一個動態的用戶模式內存分配器或堆分配器,旨在在保持性能的同時抵禦與堆相關的漏洞(例如基於堆的緩衝區溢出、釋放後使用和雙重釋放)。它提供標準的 C 分配和釋放原語(例如malloc和 free),以及 C++ 原語(例如 new 和 delete)。
與AddressSanitizer (ASan)等成熟的內存錯誤檢測器相比,Scudo 更像是一種緩解措施。
從 Android 11 版本開始,scudo 用於所有本機代碼(低內存設備除外,仍然使用 jemalloc)。在運行時,所有本機堆分配和釋放都由 Scudo 為所有可執行文件及其庫依賴項提供服務,如果在堆中檢測到損壞或可疑行為,該進程將中止。
在 Android 10 中,必須通過在 .mk 文件中設置LOCAL_SANITIZE := scudo
選項或在 .bp 文件中設置sanitize: { scudo: true, }
在每個二進製文件的基礎上啟用 scudo。
Scudo 是開源的,是 LLVM 的 compiler-rt 項目的一部分。文檔可在https://llvm.org/docs/ScudoHardenedAllocator.html獲得。 Scudo 運行時作為 Android 工具鏈的一部分提供,並且支持添加到Soong 和 Make以允許在二進製文件中輕鬆啟用分配器。
您可以使用下面描述的選項在分配器中啟用或禁用額外的緩解。
定制
分配器的一些參數可以通過以下幾種方式在每個進程的基礎上定義:
- 靜態:在程序中定義一個
__scudo_default_options
函數,返回要解析的選項字符串。此函數必須具有以下原型:extern "C" const char *__scudo_default_options()
。 - 動態:使用包含要解析的選項字符串的環境變量
SCUDO_OPTIONS
。以這種方式定義的選項會覆蓋通過__scudo_default_options
所做的任何定義。
以下選項可用。
選項 | 64 位默認 | 32 位默認值 | 描述 |
---|---|---|---|
QuarantineSizeKb | 256 | 64 | 用於延遲實際釋放塊的隔離大小(以 KB 為單位)。較低的值可能會減少內存使用,但會降低緩解的有效性;負值回退到默認值。將此和ThreadLocalQuarantineSizeKb 都設置為零會完全禁用隔離。 |
QuarantineChunksUpToSize | 2048 | 512 | 可以隔離塊的大小(以字節為單位)。 |
ThreadLocalQuarantineSizeKb | 64 | 16 | 用於卸載全局隔離的每個線程緩存的大小(以 KB 為單位)。較低的值可能會減少內存使用量,但可能會增加對全局隔離的爭用。將此值和QuarantineSizeKb 都設置為零會完全禁用隔離。 |
DeallocationTypeMismatch | false | false | 啟用關於 malloc/delete、new/free、new/delete[] 的錯誤報告 |
DeleteSizeMismatch | true | true | 啟用關於 new 和 delete 大小不匹配的錯誤報告。 |
ZeroContents | false | false | 在分配和釋放時啟用零塊內容。 |
allocator_may_return_null | false | false | 指定分配器可以在發生可恢復錯誤時返回 null,而不是終止進程。 |
hard_rss_limit_mb | 0 | 0 | 當進程的 RSS 達到此限制時,進程終止。 |
soft_rss_limit_mb | 0 | 0 | 當進程的 RSS 達到此限制時,進一步的分配將失敗或返回null (取決於allocator_may_return_null 的值),直到 RSS 回落以允許新的分配。 |
allocator_release_to_os_interval_ms | 不適用 | 5000 | 僅影響 64 位分配器。如果設置,則嘗試向操作系統釋放未使用的內存,但頻率不會超過此時間間隔(以毫秒為單位)。如果該值為負數,則不會向操作系統釋放內存。 |
abort_on_error | true | true | 如果設置,該工具會在打印錯誤消息後調用abort() 而不是_exit() 。 |
驗證
目前,沒有專門針對 Scudo 的 CTS 測試。相反,請確保在為給定二進製文件啟用或不啟用 Scudo 的情況下通過 CTS 測試,以驗證它不會影響設備。
故障排除
如果檢測到不可恢復的問題,分配器會向標準錯誤描述符顯示錯誤消息,然後終止進程。導致終止的堆棧跟踪被添加到系統日誌中。輸出通常以Scudo ERROR:
開頭,然後是問題的簡短摘要以及任何指針。
以下是當前錯誤消息及其潛在原因的列表:
-
corrupted chunk header
:塊頭的校驗和驗證失敗。這可能是由於以下兩件事之一:標頭被覆蓋(部分或全部),或者傳遞給函數的指針不是塊。 -
race on chunk header
:兩個不同的線程試圖同時操作同一個頭。這通常是在對該塊執行操作時出現競爭條件或普遍缺乏鎖定的症狀。 -
invalid chunk state
:塊不處於給定操作的預期狀態,例如,嘗試釋放它時未分配它,或者嘗試回收它時未隔離它。雙重釋放是此錯誤的典型原因。 -
misaligned pointer
:強制執行基本對齊要求:在 32 位平台上為 8 個字節,在 64 位平台上為 16 個字節。如果傳遞給我們函數的指針不適合那些,則傳遞給其中一個函數的指針不對齊。 -
allocation type mismatch
:啟用此選項時,在塊上調用的釋放函數必須與被調用以分配它的函數的類型相匹配。這種類型的不匹配會引入安全問題。 -
invalid sized delete
:當使用 C++14 大小的刪除運算符並啟用可選檢查時,釋放塊時傳遞的大小與分配塊時請求的大小不匹配。這通常是編譯器問題或被釋放對象的類型混淆。 -
RSS limit exhausted
:已超過可選指定的最大 RSS。
如果您正在調試操作系統本身的崩潰,您可以使用HWASan OS build 。如果您正在調試應用程序中的崩潰,也可以使用HWASan 應用程序構建。