Scudo 是動態使用者模式記憶體配置器,或稱「堆積」配置器,旨在防範堆積相關的安全性漏洞 (例如堆積緩衝區溢位、釋放後使用和重複釋放),同時維持效能。這個程式庫提供標準 C 分配和取消分配基本類型 (例如 malloc 和 free),以及 C++ 基本類型 (例如 new 和 delete)。
Scudo 比較像是緩解措施,而非像 AddressSanitizer (ASan) 一樣是功能齊全的記憶體錯誤偵測工具。
自 Android 11 發布以來,所有原生程式碼都使用 scudo (低記憶體裝置除外,這類裝置仍使用 jemalloc)。在執行階段,所有可執行檔及其程式庫依附元件的原生堆積分配和取消分配作業,都會由 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 |
針對新大小與刪除大小不符的情況啟用錯誤回報。 |
ZeroContents |
false |
false |
在分配和取消分配時,啟用零區塊內容。 |
allocator_may_return_null |
false |
false |
指定分配器可在發生可復原的錯誤時傳回空值,而不是終止程序。 |
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 位元分配器。如果已設定,則會嘗試將未使用的記憶體釋放給 OS,但不會超過這個間隔 (以毫秒為單位)。如果值為負數,記憶體就不會釋放給作業系統。 |
abort_on_error |
true |
true |
如果已設定,工具會在列印錯誤訊息後呼叫 abort() ,而非 _exit() 。 |
驗證
目前沒有專為 Scudo 設計的 CTS 測試。請改為確認 CTS 測試是否通過 (無論是否為特定二進位檔啟用 Scudo),以驗證這不會影響裝置。
疑難排解
如果偵測到無法復原的問題,分配器會向標準錯誤描述元顯示錯誤訊息,然後終止程序。系統記錄中會加入導致終止的堆疊追蹤記錄。
輸出內容通常會以 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 上限。
如要偵錯 OS 本身的當機問題,可以使用 HWASan OS 建構版本。如果您要偵錯應用程式中的當機問題,也可以使用 HWASan 應用程式版本。