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 位元配置器。如果已設定,系統會嘗試將未使用的記憶體釋放給作業系統,但不會超過這個間隔 (以毫秒為單位)。如果值為負值,則不會將記憶體釋放給作業系統。 |
abort_on_error |
true |
true |
如果設為此值,則工具會在輸出錯誤訊息後呼叫 abort() ,而非 _exit() 。 |
驗證
目前沒有專門針對 Scudo 進行的 CTS 測試。請改為確認在啟用或停用 Scudo 的情況下,指定二進位檔的 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 上限。
如果您要偵錯的是作業系統本身的當機問題,可以使用 HWASan OS 版本。如果您要對應用程式中的當機情形進行偵錯,也可以使用 HWASan 應用程式版本。