Con trỏ được gắn thẻ

Bắt đầu từ Android 11, đối với các quy trình 64 bit, tất cả hoạt động phân bổ vùng nhớ heap đều có thẻ xác định cách triển khai được đặt ở byte trên cùng của con trỏ trên các thiết bị có hỗ trợ kernel cho Bỏ qua byte hàng đầu (TBI) của ARM. Bất kỳ ứng dụng nào sửa đổi thẻ này sẽ bị chấm dứt khi thẻ được kiểm tra trong quá trình phân bổ. Điều này là cần thiết cho phần cứng trong tương lai có hỗ trợ Tiện ích gắn thẻ bộ nhớ ARM (MTE).

Bỏ qua byte hàng đầu

Tính năng Bỏ qua byte hàng đầu của ARM khả dụng cho mã 64 bit trong tất cả phần cứng Armv8 AArch64. Tính năng này có nghĩa là phần cứng sẽ bỏ qua byte trên cùng của con trỏ khi truy cập bộ nhớ.

TBI yêu cầu hạt nhân tương thích để xử lý chính xác các con trỏ được gắn thẻ được truyền từ không gian người dùng. Android Common Kernels từ 4.14 (Pixel 4) trở lên có các bản vá TBI bắt buộc .

Các thiết bị có hỗ trợ TBI trong nhân được phát hiện động tại thời điểm bắt đầu quá trình và thẻ phụ thuộc vào việc triển khai được chèn vào byte trên cùng của con trỏ cho tất cả các phân bổ vùng nhớ heap. Sau đó, quá trình kiểm tra sẽ được thực hiện để đảm bảo thẻ không bị cắt bớt khi giải phóng bộ nhớ.

Tính sẵn sàng của phần mở rộng gắn thẻ bộ nhớ

Tiện ích mở rộng gắn thẻ bộ nhớ (MTE) của ARM giúp giải quyết các vấn đề về an toàn bộ nhớ. MTE hoạt động bằng cách gắn thẻ các bit địa chỉ thứ 56-59 của mỗi lần cấp phát bộ nhớ trên ngăn xếp, vùng heap và toàn cục. Phần cứng và tập lệnh tự động kiểm tra xem thẻ chính xác có được sử dụng trong mỗi lần truy cập bộ nhớ hay không.

Các ứng dụng Android lưu trữ thông tin không chính xác ở byte trên cùng của con trỏ chắc chắn sẽ bị hỏng trên thiết bị hỗ trợ MTE . Con trỏ được gắn thẻ giúp dễ dàng phát hiện và từ chối việc sử dụng sai byte trên cùng của con trỏ trước khi có sẵn thiết bị MTE.

Hỗ trợ nhà phát triển

Nếu ứng dụng của bạn gặp sự cố và bạn được nhắc bằng liên kết này, điều đó có thể có nghĩa là một trong những điều sau:

  1. Ứng dụng đã cố gắng giải phóng một con trỏ không được bộ cấp phát heap của hệ thống phân bổ.
  2. Nội dung nào đó trong ứng dụng của bạn đã sửa đổi byte trên cùng của con trỏ. Không thể sửa đổi byte trên cùng của con trỏ và mã của bạn cần được thay đổi để khắc phục sự cố này.

Ví dụ về con trỏ byte trên cùng được sử dụng hoặc sửa đổi không chính xác.

  • Con trỏ tới một loại cụ thể có siêu dữ liệu dành riêng cho ứng dụng được lưu trữ trong 16 bit địa chỉ trên cùng.
  • Một con trỏ được ép lên gấp đôi rồi quay lại, làm mất các bit địa chỉ thấp hơn.
  • Mã tính toán sự khác biệt giữa địa chỉ của các biến cục bộ từ các khung ngăn xếp khác nhau như một cách để đo độ sâu đệ quy.

Một số ứng dụng có thể phụ thuộc vào các thư viện hoạt động không chính xác khi đặt byte trên cùng của con trỏ. Chúng tôi nhận thấy rằng việc khắc phục nhanh chóng những vấn đề tiềm ẩn này trong thư viện có thể là điều không cần thiết. Do đó, các ứng dụng sử dụng targetSdkLevel < 30 sẽ không bật tính năng gắn thẻ con trỏ theo mặc định. Chúng tôi cũng cung cấp một lối thoát cho các ứng dụng được xây dựng với targetSdkLevel >= 30 để giảm bớt giai đoạn chuyển tiếp.

Cửa sổ thoát được sử dụng bằng cách thêm phần sau vào tệp AndroidManifest.xml của bạn:

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

Điều này sẽ vô hiệu hóa tính năng Gắn thẻ con trỏ cho ứng dụng của bạn. Xin lưu ý rằng điều này không giải quyết được vấn đề sức khỏe mã cơ bản. Cửa thoát hiểm này sẽ biến mất trong các phiên bản Android trong tương lai vì các vấn đề thuộc loại này sẽ không tương thích với MTE .