HWASan 보고서 이해하기

HWASan 도구가 메모리 버그를 감지하면 프로세스가 abort()로 종료되고 보고서가 stderr 및 Logcat에 출력됩니다. Android의 모든 네이티브 비정상 종료와 마찬가지로 HWASan 오류는 /data/tombstones에 있습니다.

예시 보고서

일반적인 네이티브 비정상 종료와 달리 HWASan은 Tombstone 상단 근처의 Abort message 필드에 추가 정보를 전달합니다. 다음은 힙 기반 비정상 종료의 샘플입니다. 스택 버그의 경우 스택 관련 섹션의 참고를 참고하세요.

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'google/flame_hwasan/flame:Tiramisu/MASTER/7956676:userdebug/dev-keys'
Revision: 'DVT1.0'
ABI: 'arm64'
Timestamp: 2019-04-24 01:13:22+0000
pid: 11154, tid: 11154, name: sensors@1.0-ser  >>> /vendor/bin/hw/android.hardware.sensors@1.0-service <<<
signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
Abort message: '

[...]

[0x00433ae20040,0x00433ae20060) is a small unallocated heap chunk; size: 32 offset: 5








[ … regular crash dump follows …]

이 보고서는 AddressSanitizer 보고서와 유사합니다. AddressSanitizer 보고서와 다른 것은 거의 모든 HWASan 버그가 태그 불일치 오류라는 점입니다. 즉, 포인터 태그가 상응하는 메모리 태그와 일치하지 않는 메모리 액세스입니다. 다음 중 하나일 수 있습니다.

  • 스택 또는 힙에서 범위를 벗어난 액세스
  • 힙에서 Use-after-free 오류
  • 스택에서 반환 후 사용 오류

섹션

다음은 HWASan 보고서의 각 섹션에 관한 설명입니다.

액세스 오류

잘못된 메모리 액세스와 관련하여 다음과 같은 정보가 포함됩니다.

  • 액세스 유형 (READWRITE)
  • 액세스 크기(액세스하려고 시도한 바이트 수)
  • 액세스의 스레드 번호
  • 포인터 및 메모리 태그(고급 디버깅의 경우)

스택 트레이스 액세스

잘못된 메모리 액세스의 스택 트레이스입니다. 기호화하려면 기호화를 참고하세요.

원인

잘못된 액세스의 잠재적 원인입니다. 후보가 여러 개라면 가능성이 높은 항목에서 낮은 항목 순으로 정렬됩니다. 이다음에 잠재적 원인에 대한 세부정보가 표시됩니다. HWASan은 다음과 같은 원인을 진단할 수 있습니다.

  • 해제 후 사용
  • 스택 태그 불일치: 스택 use-after-return(반환 후 사용), 스택 use after-scope(범위를 벗어난 사용) 또는 범위를 벗어난 액세스일 수 있습니다.
  • 힙 버퍼 오버플로
  • 전역 오버플로

메모리 정보

액세스 중인 메모리에 관해 HWASan이 알고 있는 정보를 설명하며, 정보는 버그 유형에 따라 다를 수 있습니다.

버그 유형 원인 보고서 형식
태그 불일치 해제 후 사용 다음 보고서 형식을 사용하세요.
<address> is located N bytes inside of M-byte region [<start>, <end>)
freed by thread T0 here:
힙 버퍼 오버플로 이는 언더플로일 수도 있습니다.
<address> is located N bytes to the right of M-byte region [<start>, <end>)
allocated here:
스택 태그 불일치 스택 보고서는 오버플로 또는 언더플로와 use-after-return 버그를 구분하지 않습니다. 또한 오류의 원인인 스택 할당을 찾으려면 오프라인 기호화 단계가 필요합니다. 스택 보고서 이해하기를 참고하세요.
잘못된 무료 해제 후 사용 이중 해제 버그입니다. 이 현상이 프로세스 종료 중 발생할 경우 ODR 위반일 수 있습니다.
<address> is located N bytes inside of M-byte region [<start>, <end>)
freed by thread T0 here:
주소를 설명할 수 없음 와일드 해제 버그 (이전에 할당된 적 없는 메모리 해제) 또는 할당된 메모리가 HWASan의 사용 가능한 버퍼에서 제거된 후의 이중 해제 버그입니다.
0x... is HWAsan shadow memory 앱이 HWASan 내부에 있는 메모리를 해제하려고 했기 때문에 와일드 해제 버그입니다.

할당 해제 스택 트레이스

메모리가 할당 해제된 경우의 스택 트레이스입니다. use-after-free 또는 invalid-free 버그인 경우에만 표시됩니다. 기호화하려면 기호화를 참고하세요.

할당 스택 트레이스

메모리가 할당된 경우의 스택 트레이스입니다. 기호화하려면 기호화를 참고하세요.

고급 디버깅 정보

HWASan 보고서에는 다음과 같은 고급 디버깅 정보도 일부 포함되어 있습니다 (순서대로).

  1. 프로세스의 스레드 목록
  2. 프로세스의 스레드 목록
  3. 오작동하는 메모리 근처의 메모리 태그 값
  4. 메모리 액세스 시점의 레지스터 덤프

메모리 태그 덤프

태그 메모리 덤프를 사용하면 포인터 태그와 태그가 동일한 근처의 메모리 할당을 찾을 수 있습니다. 이러한 태그는 큰 오프셋으로 범위를 벗어난 액세스를 가리킬 수 있습니다. 태그 1개는 메모리 16바이트에 해당하며 포인터 태그는 주소의 상위 8비트입니다. 태그 메모리 덤프는 힌트를 제공할 수 있습니다. 예를 들어 다음은 오른쪽의 버퍼 오버플로입니다.

tags: ad/5c (ptr/mem)
[...]
Memory tags around the buggy address (one tag corresponds to 16 bytes):
  0x006f33ae1ff0: 0e  0e  0e  57  20  20  20  20  20  2e  5e  5e  5e  5e  5e  b5
=>0x006f33ae2000: f6  f6  f6  f6  f6  4c  ad  ad  ad  ad  ad  ad [5c] 5c  5c  5c
  0x006f33ae2010: 5c  04  2e  2e  2e  2e  2e  2f  66  66  66  66  66  80  6a  6a
Tags for short granules around the buggy address (one tag corresponds to 16 bytes):
  0x006f33ae1ff0: ab  52  eb  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..
=>0x006f33ae2000: ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  .. [..] ..  ..  ..
  0x006f33ae2010: ..  5c  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..

포인터 태그와 일치하는 왼쪽 ad 태그의 6 × 16 = 96바이트 실행에 주목하세요.

할당 크기가 16의 배수가 아닌 경우 크기의 나머지는 메모리 태그로 저장되고 태그는 짧은 그래뉼 태그로 저장됩니다. 이전 예에서 굵게 표시되어 있으며 할당 태그가 지정된 ad 바로 뒤에 태그 5c의 5 × 16 + 4 = 84바이트 할당이 있습니다.

0 메모리 태그 (예: tags: ad/00 (ptr/mem))는 스택 사용 후 반환 버그를 나타냅니다.

레지스터 덤프

HWASan 보고서의 레지스터 덤프는 잘못된 메모리 액세스를 실행한 명령에 해당합니다. 이 덤프 뒤에는 일반 Android 신호 핸들러의 또 다른 레지스터 덤프가 나옵니다. 두 번째 덤프는 무시합니다. HWASan이 abort()를 호출할 때 표시되며 버그와는 관련이 없습니다.

기호화

스택 트레이스에서 함수 이름과 줄 번호를 가져오고 use-after-scope 버그의 변수 이름을 가져오려면 오프라인 기호화 단계가 필요합니다.

최초 설정: llvm-symbolizer 설치

기호화하려면 시스템에 llvm-symbolizer가 설치되어 있고 $PATH에서 액세스할 수 있어야 합니다. Debian에서는 sudo apt install llvm을 사용하여 설치할 수 있습니다.

기호 파일 가져오기

기호화를 위해서는 기호가 포함된 제거되지 않은 바이너리가 필요합니다. 위치는 빌드 유형에 따라 다릅니다.

  • 로컬 빌드의 경우 기호 파일은 out/target/product/<product>/symbols/에 있습니다.
  • AOSP 빌드 (예: Android Flash Tool에서 플래시됨)의 경우 빌드는 Android CI에 있습니다. 빌드의 아티팩트에는 ${PRODUCT}-symbols-${BUILDID}.zip 파일이 있습니다.
  • 조직의 내부 빌드는 기호 파일 가져오기와 관련된 조직 문서를 참고하세요.

기호화

hwasan_symbolize --symbols <DECOMPRESSED_DIR>/out/target/product/*/symbols < crash

스택 보고서 이해하기

스택 변수에서 발생하는 버그의 경우 HWASan 보고서에 다음과 같은 세부정보가 포함됩니다.

Cause: stack tag-mismatch
Address 0x007d4d251e80 is located in stack of thread T64
Thread: T64 0x0074000b2000 stack: [0x007d4d14c000,0x007d4d255cb0) sz: 1088688 tls: [0x007d4d255fc0,0x007d4d259000)
Previously allocated frames:
  record_addr:0x7df7300c98 record:0x51ef007df3f70fb0  (/apex/com.android.art/lib64/libart.so+0x570fb0)
  record_addr:0x7df7300c90 record:0x5200007df3cdab74  (/apex/com.android.art/lib64/libart.so+0x2dab74)
  [...]

HWASan은 스택 버그를 파악할 수 있도록 과거 스택 프레임을 추적합니다. HWASan은 버그 신고에서 사람이 읽을 수 있는 콘텐츠로 이를 변환하지 않으므로 추가 기호화 단계가 필요합니다.

ODR 위반

HWASan에서 신고한 일부 use-after-free 버그는 단일 정의 규칙 (ODR) 위반을 나타낼 수도 있습니다. ODR 위반은 동일한 변수가 한 프로그램에서 여러 번 정의된 경우 발생합니다. 이는 변수가 여러 번 폐기됨을 의미하기도 하며 use-after-free 오류를 야기할 수 있습니다.

기호화 후 ODR 위반은 __cxa_finalize를 통한 use-after-free 오류가 잘못된 액세스 스택과 여기서 반환된 스택 모두에서 발생했음을 보여줍니다. 여기서 이전에 할당된 스택은 __dl__ZN6soinfo17call_constructorsEv를 포함하고, 스택에서 상위에 있는 변수를 정의하는 프로그램 내 위치를 가리켜야 합니다.

정적 라이브러리를 사용하면 ODR이 위반될 수 있습니다. C++ 글로벌을 정의하는 정적 라이브러리가 여러 공유 라이브러리 또는 실행 파일과 연결된 경우 동일한 기호의 여러 정의가 동일한 주소 공간에 존재할 수 있으며 이로 인해 ODR 오류가 발생할 수 있습니다.

문제 해결

이 섹션에서는 몇 가지 오류와 해결 방법을 설명합니다.

HWAddressSanitizer can not describe address in more detail

가끔 HWASan에서 이전 메모리 할당에 관한 정보를 저장할 공간이 부족할 수 있습니다. 이 경우 보고서에 즉시 메모리 액세스를 위한 스택 트레이스 하나만 포함되고 이어서 다음 메모가 표시됩니다.

HWAddressSanitizer can not describe address in more detail.

테스트를 여러 번 실행하면 이 문제가 해결되는 경우도 있습니다. 또 다른 옵션은 HWASan 기록 크기를 늘리는 것입니다. build/soong/cc/sanitize.go (hwasanGlobalOptions 찾기) 또는 프로세스 환경 (adb shell echo $HWASAN_OPTIONS를 시도하여 현재 설정 확인하기)에서 이를 전역적으로 실행할 수 있습니다.

액세스된 메모리가 매핑되지 않거나 HWASan을 인식하지 않는 할당자에 의해 할당되는 경우에도 이 오류가 발생할 수 있습니다. 이 경우 비정상 종료 헤더에 나열된 mem 태그는 일반적으로 00입니다. 전체 Tombstone에 액세스할 수 있는 경우 메모리 맵 덤프를 참조하여 주소가 속하는 매핑 (있는 경우)을 찾는 것이 좋을 수 있습니다.

동일한 대화목록에 중첩된 버그

이는 HWASan 비정상 종료 보고서를 생성하는 동안 버그가 발생했음을 의미합니다. 이는 일반적으로 HWASan 런타임의 버그로 인해 발생합니다. 버그를 신고하고 가능한 경우 문제를 재현하는 방법에 관한 안내를 제공합니다.