태그가 지정된 포인터

Android 11부터 64비트 프로세스의 경우 모든 힙 할당에는 ARM Top-byte Ignore(TBI) 커널 지원이 있는 기기에서 포인터의 최상위 바이트에 설정된 구현 정의 태그가 있습니다. 이 태그를 수정하는 모든 애플리케이션은 할당 해제 중에 태그를 확인되면 종료됩니다. 이는 ARM Memory Tagging Extension(MTE)을 지원하는 향후 하드웨어에 필요합니다.

Top-byte Ignore

ARM의 Top-byte Ignore 기능은 모든 Armv8 AArch64 하드웨어에서 64비트 코드에 사용할 수 있습니다. 이 기능은 하드웨어가 메모리에 액세스할 때 포인터의 최상위 바이트를 무시한다는 것을 의미합니다.

TBI에는 사용자 공간에서 전달된 태그가 지정된 포인터를 올바르게 처리하는 호환 커널이 필요합니다. 4.14(Pixel 4) 이상의 Android 일반 커널에는 필수 TBI 패치가 포함됩니다.

커널에서 TBI를 지원하는 기기는 프로세스 시작 시간에 동적으로 감지되며 구현 종속 태그는 모든 힙 할당 포인터의 최상위 바이트에 삽입됩니다. 그런 다음 메모리 할당을 해제할 때 태그가 잘리지 않았는지 확인합니다.

Memory Tagging Extension 준비

ARM의 Memory Tagging Extension(MTE)은 메모리 안전 문제를 해결하는 데 도움이 됩니다. MTE는 스택, 힙, 전역에서 각 메모리 할당의 56번째~59번째 주소 비트를 태그하여 작동합니다. 하드웨어와 명령 집합은 메모리 액세스 시마다 올바른 태그가 사용되는지 자동으로 확인합니다.

포인터의 최상위 바이트에 정보를 잘못 저장하는 Android 앱은 MTE 지원 기기에서 작동이 중단됩니다. 태그가 지정된 포인터를 사용하면 MTE 기기를 사용하기 전에 포인터의 최상위 바이트를 잘못 사용하는 것을 더 쉽게 감지하여 거부할 수 있습니다.

개발자 지원

앱이 비정상 종료되고 이 링크가 표시되는 경우 다음 중 하나가 원인일 수 있습니다.

  1. 애플리케이션이 시스템의 힙 할당자에서 할당하지 않은 포인터를 해제하려고 했습니다.
  2. 앱의 어떤 부분이 포인터의 최상위 바이트를 수정했습니다. 포인터의 최상위 바이트는 수정할 수 없고 코드를 변경하여 이 문제를 해결해야 합니다.

잘못 사용되거나 수정되는 최상위 바이트 포인터의 예는 다음과 같습니다.

  • 특정 유형 포인터에는 최상위 16개 주소 비트에 저장된 애플리케이션별 메타데이터가 있습니다.
  • 포인터가 double로 전송되었다가 돌아오므로 하위 주소 비트가 손실됩니다.
  • 재귀 깊이를 측정하는 방법으로 다양한 스택 프레임에서 로컬 변수 주소 간의 차이를 계산하는 코드입니다.

일부 애플리케이션은 포인터의 최상위 바이트가 설정될 때 잘못 동작하는 라이브러리에 의존할 수 있습니다. 라이브러리의 이러한 기본 문제를 빠르게 해결하기는 쉽지 않은 일일 수 있습니다. 따라서 targetSdkLevel < 30을 사용하는 애플리케이션에는 기본적으로 포인터 태그 지정이 사용 설정되지 않습니다. targetSdkLevel >= 30으로 빌드된 애플리케이션의 전환기가 수월하도록 이스케이프 해치도 제공합니다.

이스케이프 해치는 AndroidManifest.xml 파일에 다음을 추가하여 사용합니다.

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

이렇게 하면 애플리케이션의 포인터 태그 지정 기능이 사용 중지됩니다. 기본 코드 상태 문제는 해결되지 않습니다. 이 이스케이프 해치는 향후 Android 버전에서 사라집니다. 이러한 성격의 문제가 MTE와 호환되지 않기 때문입니다.