Arm Memory Tagging Extension

Arm v9 引入了 Arm記憶體標記擴充(MTE),這是標記記憶體的硬體實作

在較高層級上,MTE 使用附加元資料標記每個記憶體分配/釋放。它將一個標籤分配給一個記憶體位置,然後該標籤可以與引用該記憶體位置的指標相關聯。在運行時,CPU 檢查每次載入和儲存時指標和元資料標籤是否匹配。

在 Android 12 中,核心和使用者空間堆記憶體分配器可以使用元資料來擴充每個分配。這有助於檢測釋放後使用和緩衝區溢位錯誤,這是我們程式碼庫中記憶體安全錯誤的最常見來源。

MTE 操作模式

MTE有三種工作模式:

  • 同步模式(SYNC)
  • 非同步模式(ASYNC)
  • 非對稱模式(ASYMM)

同步模式(SYNC)

此模式針對錯誤檢測的正確性與效能進行了最佳化,並且在可接受更高的效能開銷時可以用作精確的錯誤檢測工具。啟用後,MTE SYNC 將充當安全緩解措施。如果標籤不匹配,處理器會立即中止執行,並使用SIGSEGV (代碼SEGV_MTESERR )以及有關記憶體存取和故障位址的完整資訊終止進程。

我們建議在測試期間使用此模式作為 HWASan/KASAN 的替代方案,或在生產中當目標程序代表易受攻擊的攻擊面時使用此模式。此外,當非同步模式表明存在錯誤時,可以透過使用執行時間 API 將執行切換到同步模式來獲得準確的錯誤報告。

在 SYNC 模式下運行時, Android 分配器記錄所有分配和釋放的堆疊跟踪,並使用它們提供更好的錯誤報告,其中包括內存錯誤的解釋,例如釋放後使用或緩衝區溢出以及堆疊相關記憶事件的痕跡。此類報告提供了更多上下文信息,並使錯誤更容易追蹤和修復。

非同步模式(ASYNC)

此模式針對錯誤報告的準確性進行了效能最佳化,並且可用作記憶體安全錯誤的低開銷偵測。
如果標記不匹配,處理器將繼續執行,直到最近的核心條目(例如,系統呼叫或計時器中斷),然後使用SIGSEGV (代碼SEGV_MTEAERR )終止進程,而不記錄錯誤位址或記憶體存取。
我們建議在經過良好測試的程式碼庫的生產中使用此模式,其中已知記憶體安全錯誤的密度較低,這是透過在測試期間使用 SYNC 模式來實現的。

非對稱模式(ASYMM)

Arm v8.7-A 中的一個附加功能是不對稱 MTE 模式,提供記憶體讀取的同步檢查和記憶體寫入的非同步檢查,其效能與 ASYNC 模式類似。在大多數情況下,此模式是 ASYNC 模式的改進,我們建議在可用時使用它而不是 ASYNC。

因此,以下所描述的 API 均未提及非對稱模式。相反,可以將作業系統配置為在請求非同步時始終使用非對稱模式。有關詳細信息,請參閱“配置特定於 CPU 的首選 MTE 等級”部分。

使用者空間中的 MTE

以下各節介紹如何為系統進程和應用程式啟用 MTE。預設情況下,MTE 處於停用狀態,除非為特定進程設定了下列選項之一(請參閱下方為哪些元件啟用了 MTE)。

使用建置系統啟用 MTE

作為進程範圍的屬性,MTE 由主執行檔的建置時間設定控制。以下選項允許更改單一可執行檔或來源樹中的整個子目錄的此設定。在庫或任何既不可執行也不可測試的目標上,該設定將被忽略。

1. 在Android.bp中啟用 MTE(範例),對於特定項目:

行動通訊模式環境
異步MTE
  sanitize: {
  memtag_heap: true,
  }
同步MTE
  sanitize: {
  memtag_heap: true,
  diag: {
  memtag_heap: true,
  },
  }

或在Android.mk:

行動通訊模式環境
Asynchronous MTE LOCAL_SANITIZE := memtag_heap
Synchronous MTE LOCAL_SANITIZE := memtag_heap
LOCAL_SANITIZE_DIAG := memtag_heap

2. 使用產品變數在來源樹中的子目錄上啟用 MTE:

MTE模式包含列表排除列表
非同步PRODUCT_MEMTAG_HEAP_ASYNC_INCLUDE_PATHS MEMTAG_HEAP_ASYNC_INCLUDE_PATHS PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS MEMTAG_HEAP_EXCLUDE_PATHS
同步PRODUCT_MEMTAG_HEAP_SYNC_INCLUDE_PATHS MEMTAG_HEAP_SYNC_INCLUDE_PATHS

或者

行動通訊模式環境
異步MTE MEMTAG_HEAP_ASYNC_INCLUDE_PATHS
同步MTE MEMTAG_HEAP_SYNC_INCLUDE_PATHS

或透過指定可執行檔的排除路徑:

行動通訊模式環境
異步MTE PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS MEMTAG_HEAP_EXCLUDE_PATHS
同步MTE

範例(與PRODUCT_CFI_INCLUDE_PATHS的用法類似)

  PRODUCT_MEMTAG_HEAP_SYNC_INCLUDE_PATHS=vendor/$(vendor)
  PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS=vendor/$(vendor)/projectA \
                                    vendor/$(vendor)/projectB

使用系統屬性啟用 MTE

可以透過設定以下系統屬性在運行時覆蓋上述建置設定:

arm64.memtag.process.<basename> = (off|sync|async)

其中basename代表可執行檔的基本名稱。

例如,要將/system/bin/ping/data/local/tmp/ping設定為使用非同步 MTE,請使用adb shell setprop arm64.memtag.process.ping async

使用環境變數啟用 MTE

覆寫建置設定的另一種方法是定義環境變數: MEMTAG_OPTIONS=(off|sync|async)如果同時定義了環境變數和系統屬性,則該變數優先。

為應用程式啟用 MTE

如果未指定,預設會停用 MTE,但想要使用 MTE 的應用程式可以透過在AndroidManifest.xml中的<application><process>標記下設定android:memtagMode來實現。

android:memtagMode=(off|default|sync|async)

<application>標記上設定時,此屬性會影響應用程式使用的所有進程,並且可以透過設定<process>標記來覆寫各個進程。

為了進行實驗,相容性變更可用於為未在清單中指定任何值(或指定default )的應用程式設定memtagMode屬性的預設值。
這些可以在全域設定選單中的System > Advanced > Developer options > App Compatibility Changes下找到。設定NATIVE_MEMTAG_ASYNCNATIVE_MEMTAG_SYNC為特定應用程式啟用 MTE。
或者,可以使用am命令進行設置,如下所示:

$ adb shell am compat enable NATIVE_MEMTAG_[A]SYNC my.app.name

建構MTE系統鏡像

我們強烈建議在開發和啟動期間在所有本機二進位上啟用 MTE。如果在測試版本中啟用,這有助於及早檢測記憶體安全錯誤並提供實際的使用者覆蓋範圍。

我們強烈建議在開發期間在所有本機二進位上以同步模式啟用 MTE

SANITIZE_TARGET=memtag_heap SANITIZE_TARGET_DIAG=memtag_heap m

與建置系統中的任何變數一樣, SANITIZE_TARGET可以用作環境變數或make設定(例如,在product.mk檔案中)。
請注意,這將為所有本機進程啟用 MTE,但不適用於可以按照上述說明啟用 MTE 的應用程式(從zygote64派生)。

配置特定於 CPU 的首選 MTE 級別

在某些 CPU 上,非同步甚至同步模式下的 MTE 效能可能與非同步模式相似。因此,當請求不太嚴格的檢查模式時,值得對這些 CPU 啟用更嚴格的檢查,以便獲得更嚴格檢查的錯誤偵測優勢,而不會降低效能。
預設情況下,配置為在非同步模式下運行的進程將在所有 CPU 上以非同步模式運作。若要將核心配置為在特定 CPU 上以 SYNC 模式執行這些進程,必須在開機時將值sync 寫入sysfs條目/sys/devices/system/cpu/cpu<N>/mte_tcf_preferred 。這可以透過初始化腳本來完成。例如,要將 CPU 0-1 配置為在 SYNC 模式下運行 ASYNC 模式進程,並將 CPU 2-3 配置為在 ASYMM 模式下運行,可以將下列內容新增至供應商 init 腳本的 init 子句:

  write /sys/devices/system/cpu/cpu0/mte_tcf_preferred sync
  write /sys/devices/system/cpu/cpu1/mte_tcf_preferred sync
  write /sys/devices/system/cpu/cpu2/mte_tcf_preferred asymm
  write /sys/devices/system/cpu/cpu3/mte_tcf_preferred asymm

在同步模式下運行的非同步模式進程的邏輯刪除將包含記憶體錯誤位置的精確堆疊追蹤。但是,它們不會包含分配或釋放堆疊追蹤。僅當進程配置為在同步模式下運行時,這些堆疊追蹤才可用。

int mallopt(M_THREAD_DISABLE_MEM_INIT, level)

其中level為 0 或 1。
停用 malloc 中的記憶體初始化,並避免更改記憶體標籤,除非為了正確性所必需。

int mallopt(M_MEMTAG_TUNING, level)

其中level是:

  • M_MEMTAG_TUNING_BUFFER_OVERFLOW
  • M_MEMTAG_TUNING_UAF

選擇標籤分配策略。

  • 預設為M_MEMTAG_TUNING_BUFFER_OVERFLOW
  • M_MEMTAG_TUNING_BUFFER_OVERFLOW - 透過為相鄰分配分配不同的標籤值,實現線性緩衝區溢位和下溢錯誤的確定性偵測。此模式檢測釋放後使用錯誤的機會略有減少,因為每個記憶體位置只有一半可能的標記值可用。請記住,MTE 無法偵測相同標籤顆粒(16 位元組對齊區塊)內的溢出,並且即使在此模式下也可能會錯過小溢出。這種溢出不可能是記憶體損壞的原因,因為一個顆粒內的記憶體永遠不會用於多次分配。
  • M_MEMTAG_TUNING_UAF - 啟用獨立隨機標籤,以統一約 93% 的機率檢測空間(緩衝區溢位)和時間(釋放後使用)錯誤。

除了上述 API 之外,有經驗的使用者可能還需要了解以下內容:

  • 設定PSTATE.TCO硬體暫存器可以暫時抑制標籤檢查(範例)。例如,複製具有未知標籤內容的記憶體範圍或解決熱循環中的效能瓶頸時。
  • 使用M_HEAP_TAGGING_LEVEL_SYNC時,系統崩潰處理程序提供額外信息,例如分配和釋放堆疊追蹤。此功能需要存取標記位,並透過在設定訊號處理程序時傳遞SA_EXPOSE_TAGBITS標誌來啟用。任何設定自己的訊號處理程序並將未知崩潰委託給系統的程序都建議執行相同的操作。

核心中的 MTE

若要為核心啟用 MTE 加速 KASAN,請使用CONFIG_KASAN=yCONFIG_KASAN_HW_TAGS=y配置核心。從Android 12-5.10開始,這些配置在 GKI 核心上預設啟用。
這可以在啟動時使用以下命令列參數進行控制:

  • kasan=[on|off] - 啟用或停用 KASAN(預設值: on
  • kasan.mode=[sync |async ] - 選擇同步與非同步模式(預設: sync
  • kasan.stacktrace=[on|off] - 是否收集堆疊追蹤(預設值: on
    • 堆疊追蹤收集還需要stack_depot_disable=off
  • kasan.fault=[report|panic] - 是否只列印報告,或也使核心發生恐慌(預設值: report )。無論此選項為何,在第一次報告錯誤後都會停用標籤檢查。

我們強烈建議在啟動、開發和測試期間使用 SYNC 模式。應使用環境變數建置系統為所有進程全域啟用此選項。在這種模式下,可以在開發過程的早期檢測到錯誤,更快地穩定程式碼庫,並避免在生產後期檢測錯誤的成本。

我們強烈建議在生產中使用非同步模式。這提供了一種低開銷工具,用於檢測進程中記憶體安全錯誤的存在以及進一步的深度防禦。一旦偵測到錯誤,開發人員就可以利用執行時間 API 切換到同步模式,並從一組取樣的使用者中獲得準確的堆疊追蹤。

我們強烈建議為 SoC 配置特定於 CPU 的首選 MTE 等級。非同步模式通常具有與非同步模式相同的效能特徵,並且幾乎總是優於非同步模式。小型有序內核通常在所有三種模式下表現出相似的性能,並且可以配置為首選 SYNC。

開發人員應透過檢查/data/tombstoneslogcat或監控供應商DropboxManager管道中的最終使用者錯誤來檢查是否有當機。有關調試 Android 本機代碼的更多信息,請參閱此處的資訊。

支援 MTE 的平台組件

在 Android 12 中,許多安全關鍵系統元件使用 MTE ASYNC 來偵測最終用戶崩潰並充當額外的深度防禦層。這些組件是:

  • 網路守護程式和實用程式( netd除外)
  • 藍牙、SecureElement、NFC HAL 和系統應用程式
  • statsd程式
  • system_server
  • zygote64 (允許應用程式選擇使用 MTE)

這些目標是根據以下標準選擇的:

  • 特權程序(定義為有權存取 unprivileged_app SELinux 網域無法存取的內容的進程)
  • 處理不可信的輸入(二法則
  • 可接受的效能下降(下降不會造成用戶可見的延遲)

我們鼓勵供應商遵循上述標準,在生產中為更多組件啟用 MTE。在開發過程中,我們建議使用 SYNC 模式測試這些元件,以偵測容易修復的錯誤,並評估非同步對其效能的影響。
未來,Android 計畫以即將推出的硬體設計的效能特性為指導,擴大啟用 MTE 的系統元件清單。