飛毛腿

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 應用程序構建