Scudo 是一個動態使用者模式記憶體分配器或堆疊分配器,旨在抵禦與堆疊相關的漏洞(例如基於堆疊的緩衝區溢位、釋放後使用和雙重釋放),同時保持效能。它提供標準的 C 分配和釋放原語(例如malloc和 free)以及 C++ 原語(例如 new 和 delete)。
Scudo 比AddressSanitizer (ASan)等成熟的記憶體錯誤偵測器更像是一種緩解措施。
自 Android 11 版本以來,scudo 用於所有本機程式碼(低記憶體裝置上仍使用 jemalloc 除外)。在運行時,所有本機堆分配和釋放均由 Scudo 為所有可執行檔案及其庫依賴項提供服務,如果在堆中偵測到損壞或可疑行為,則進程將中止。
Scudo 是開源的,是 LLVM 編譯器-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 | 啟用有關新建和刪除大小不符的錯誤報告。 |
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 建置。如果您正在調試應用程式中的崩潰,也可以使用HWASan 應用程式建置。