Kể từ Android 11, đối với các quy trình 64 bit, tất cả các lượt phân bổ vùng nhớ khối xếp đều có một thẻ được xác định triển khai được đặt trong byte trên cùng của con trỏ trên các thiết bị có hỗ trợ nhân cho tính năng Bỏ qua byte trên cùng (TBI) của ARM. Mọi ứng dụng sửa đổi thẻ này sẽ bị chấm dứt khi thẻ được kiểm tra trong quá trình giải phóng. Điều này là cần thiết đối với phần cứng trong tương lai có hỗ trợ Tiện ích gắn thẻ bộ nhớ ARM (MTE).
Bỏ qua byte trên cùng
Tính năng Bỏ qua byte quan trọng nhất của ARM có sẵn 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 bỏ qua byte trên cùng của con trỏ khi truy cập vào bộ nhớ.
TBI yêu cầu một 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. Các hạt nhân Android Common 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 một cách linh động tại thời điểm bắt đầu quy trình và một 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 lượt phân bổ vùng nhớ khối xếp. Sau đó, một quy trình kiểm tra sẽ chạy để đảm bảo thẻ không bị cắt bớt khi giải phóng bộ nhớ.
Chuẩn bị Tiện ích gắn thẻ bộ nhớ
Tiện ích 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ỉ từ 56 đến 59 của mỗi lượt phân bổ bộ nhớ trên ngăn xếp, vùng nhớ khối xếp và các giá trị chung. Phần cứng và bộ hướng dẫn sẽ tự động kiểm tra để đảm bảo sử dụng đúng thẻ trong mỗi lần truy cập bộ nhớ.
Các ứng dụng Android lưu trữ thông tin không chính xác trong byte trên cùng của con trỏ được đảm bảo sẽ bị lỗi 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 không chính xác của byte trên cùng của con trỏ trước khi có thiết bị MTE.
Hỗ trợ dành cho nhà phát triển
Nếu ứng dụng của bạn gặp sự cố và bạn được nhắc nhở bằng đường liên kết này, thì điều đó có thể có nghĩa là một trong những điều sau:
- Ứng dụng đã cố gắng giải phóng một con trỏ không được bộ phân bổ vùng nhớ khối xếp của hệ thống phân bổ.
- Có gì đó trong ứng dụng của bạn đã sửa đổi byte trên cùng của con trỏ. Bạn không thể sửa đổi byte trên cùng của con trỏ và cần thay đổi mã để khắc phục vấn đề này.
Ví dụ về con trỏ byte trên cùng bị sử dụng hoặc sửa đổi không chính xác.
- Con trỏ đến 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ỉ hàng đầu.
- Con trỏ được truyền sang double 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 để đ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 nhanh chóng khắc phục những vấn đề cơ bản này trong thư viện có thể không hề đơn giản. 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 cửa sổ thoát cho các ứng dụng được tạo bằng targetSdkLevel >= 30
để giúp dễ dàng chuyển đổi.
Bạn có thể sử dụng lối thoát bằng cách thêm nội dung sau vào tệp AndroidManifest.xml
:
<application android:allowNativeHeapPointerTagging="false"> ... </application>
Thao tác này sẽ tắt tính năng Gắn con trỏ cho ứng dụng. Việc này không giải quyết được vấn đề cơ bản về trạng thái của mã. Lối thoát 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.