標記指針

從 Android 11 開始,對於 64 位進程,在內核支持 ARM 頂部字節忽略 (TBI) 的設備上,所有堆分配都在指針的頂部字節中設置了一個實現定義的標記。在解除分配期間檢查標籤時,任何修改此標籤的應用程序都會終止。這對於具有ARM 內存標記擴展(MTE) 支持的未來硬件是必需的。

高字節忽略

ARM 的最高字節忽略功能適用於所有 Armv8 AArch64 硬件中的 64 位代碼。此功能意味著硬件在訪問內存時會忽略指針的最高字節。

TBI 需要一個兼容的內核來正確處理從用戶空間傳遞的標記指針。來自 4.14 (Pixel 4) 及更高版本的 Android 通用內核具有所需的TBI 補丁

在進程啟動時動態檢測內核中支持 TBI 的設備,並將一個依賴於實現的標記插入到所有堆分配的指針的頂部字節中。在此之後,運行檢查以確保在釋放內存時標籤沒有被截斷。

內存標記擴展準備就緒

ARM 的內存標記擴展 (MTE) 有助於解決內存安全問題。 MTE 通過在堆棧、堆和全局變量上標記每個內存分配的第 56-59 個地址位來工作。硬件和指令集會在每次內存訪問時自動檢查是否使用了正確的標籤。

保證在支持 MTE 的設備上錯誤地將信息存儲在指針的最高字節中的 Android 應用程序會中斷。標記指針使在 MTE 設備可用之前更容易檢測和拒絕指針頂部字節的錯誤使用。

開發者支持

如果您的應用程序崩潰並且系統提示您使用此鏈接,則可能意味著以下情況之一:

  1. 應用程序試圖釋放一個未被系統堆分配器分配的指針。
  2. 您的應用程序中的某些內容修改了指針的最高字節。指針的最高字節無法修改,您的代碼需要更改以解決此問題。

錯誤使用或修改最高字節指針的示例。

  • 指向特定類型的指針具有存儲在前 16 個地址位中的應用程序特定元數據。
  • 一個指針轉換為 double 然後返回,丟失低地址位。
  • 計算來自不同堆棧幀的局部變量地址之間的差異的代碼,作為測量遞歸深度的一種方式。

某些應用程序可能依賴於在設置指針的最高字節時行為不正確的庫。我們認識到快速修復庫中的這些潛在問題可能並非易事。因此,使用targetSdkLevel < 30的應用程序默認不會啟用指針標記。我們還為使用targetSdkLevel >= 30構建的應用程序提供了一個逃生口,以緩解過渡期。

通過將以下內容添加到您的AndroidManifest.xml文件來使用逃生艙口:

  <application android:allowNativeHeapPointerTagging="false">
  ...
  </application>

這將為您的應用程序禁用指針標記功能。請注意,這並不能解決底層代碼健康問題。這種逃生艙口將在未來的 Android 版本中消失,因為這種性質的問題將與MTE不兼容。