Scudo

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