Scudo

Scudo 是一種動態使用者模式記憶體配置器,或稱「堆積」分配器,可靈活應對堆積相關的安全漏洞 (例如堆積型緩衝區溢位釋放後使用重複釋放),同時維持效能。提供標準 C 配置和取消配置基本功能 (例如 malloc 和 Free),以及 C++ 基本功能 (例如新增和刪除)。

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 應用程式版本