Omówienie raportów HWASan

Gdy narzędzie HWASan wykryje błąd pamięci, proces jest zamykany za pomocą funkcji abort(), a raport jest drukowany w stderr i logcat. Podobnie jak wszystkie natywne awarie na Androidzie, błędy HWASan są uwzględnione w sekcji /data/tombstones.

Przykładowy raport

W odróżnieniu od zwykłych awarii natywnych HWASan zawiera dodatkowe informacje w polu Abort message (Anuluj komunikat) u góry nagłówka. Oto przykładowy błąd powodowany przez stos. Informacje o błędach w kodzie źródłowym znajdziesz w notatce dotyczącej sekcji dotyczących kodu źródłowego.

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
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 …]

Jest to podobne do raportu AddressSanitizer. W przeciwieństwie do nich prawie wszystkie błędy HWASan to błędy niezgodności tagów, czyli dostęp do pamięci, w którym tag wskaźnika nie pasuje do odpowiedniego tagu pamięci. Może to być:

  • Dostęp poza zakres stosu lub stosu dynamicznego
  • Błąd „use-after-free” w stercie
  • Błąd „use-after-return” na stosie

Sekcje

Poniżej znajdziesz wyjaśnienie poszczególnych sekcji raportu HWASan.

Błąd dostępu

Zawiera informacje o nieprawidłowym dostępie do pamięci, w tym:

  • Typ dostępu (READ lub WRITE)
  • Rozmiar dostępu (ile bajtów zostało odczytanych)
  • Numer wątku dostępu
  • tagi wskaźnika i pamięci (do zaawansowanego debugowania).

Dostęp do ścieżki śledzenia

Zrzut stosu z informacjami o nieprawidłowym dostępie do pamięci. Aby dowiedzieć się więcej o symbolizacji, zapoznaj się z artykułem Symbolizacja.

Przyczyna

Możliwa przyczyna nieprawidłowego dostępu. Jeśli jest ich więcej, są one wymienione w kolejności malejącej prawdopodobieństwa. Poprzedza szczegółowe informacje o potencjalnej przyczynie. HWASan może zdiagnozować te przyczyny:

  • Używanie po zakończeniu okresu bezpłatnego
  • niezgodność tagu stosu, która może być spowodowana użyciem stosu po instrukcji return, użyciem stosu po zakresie lub wyjściem poza zakres.
  • Przepełnienie bufora stosu
  • Global overflow

Informacje o pamięci

Opisuje, co HWASan wie o pamięci, do której uzyskuje dostęp. Może się to różnić w zależności od typu błędu:

Typ błędu Przyczyna Format raportu
Niezgodność tagu Używanie po zakończeniu okresu bezpłatnego Użyj tego formatu raportu:
<address> is located N bytes inside of M-byte region [<start>, <end>)
freed by thread T0 here:
Przepełnienie bufora stosu Pamiętaj, że może to być też przepełnienie.
<address> is located N bytes to the right of M-byte region [<start>, <end>)
allocated here:
Niezgodność tagu stosu Raporty stosu nie rozróżniają błędów przepełnienia, niedopełnienia i użycia po powrocie. Dodatkowo, aby znaleźć alokację stosu, która jest źródłem błędu, wymagany jest krok symbolizacji offline. Zobacz Informacje o raportach z warstw.
Nieprawidłowy wolny Używanie po okresie bezpłatnym Błąd podwójnego zwolnienia. Jeśli tak się dzieje podczas zamykania procesu, może to oznaczać naruszenie zasad rozwiązywania sporów online.
<address> is located N bytes inside of M-byte region [<start>, <end>)
freed by thread T0 here:
Nie można opisać adresu Albo wolna pamięć (wolna pamięć, która nie została wcześniej przydzielona), albo podwójna wolna pamięć po usunięciu przydzielonej pamięci z wolnego bufora HWASan.
0x... to pamięć cienia HWAsan A wild free, ponieważ aplikacja próbowała zwolnić pamięć wewnętrzną HWASan.

Zrzut stosu dotyczący zwalniania zasobów

śledzenie zrzutu stosu, gdzie pamięć została zwolniona; Widoczne tylko w przypadku błędów typu use-after-free lub invalid-free. Aby dowiedzieć się, jak to zrobić, przeczytaj artykuł Symbolizacja.

Zrzut stosu alokacji

śledzenie zrzutu stosu, gdzie pamięć została przydzielona; Aby dowiedzieć się, jak to zrobić, przeczytaj artykuł Symbolizacja.

Zaawansowane informacje o debugowaniu

Raport HWASan zawiera też informacje o zaawansowanym debugowaniu, w tym (w podanej kolejności):

  1. Lista wątków w procesie
  2. Lista wątków w procesie
  3. Wartość tagów pamięci w pobliżu pamięci z błędem
  4. zrzut rejestrów w miejscu dostępu do pamięci,

Zrzut danych tagu pamięci

Dump pamięci tagu umożliwia znalezienie w pobliżu przydziałów pamięci z tym samym tagiem co tag wskaźnika. Te tagi mogą wskazywać na dostęp poza zakresem z dużym przesunięciem. Jeden tag odpowiada 16 bajtom pamięci; tag wskaźnika to 8 najstarszych bitów adresu. Zrzut pamięci tagów może zawierać wskazówki. Na przykład poniżej znajduje się przepełnienie bufora po prawej stronie:

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  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..

Zwróć uwagę na ciąg 6 × 16 = 96 bajtów tagów ad po lewej stronie, które pasują do tagu wskaźnika.

Jeśli rozmiar alokacji nie jest wielokrotnością 16, reszta jest przechowywana jako tag pamięci, a ten z kolei jako krótki tag granulkowy. W poprzednim przykładzie tuż po oznaczonym pogrubioną czcionką przypisie ad mamy przypisany do tagu 5c przydział o długości 5 × 16 + 4 = 84 bajty.

Tag pamięci o wartości 0 (np. tags: ad/00 (ptr/mem)) wskazuje błąd polegający na użyciu stosu po powrocie.

Zrzut rejestru

Dane zrzutu rejestru w raportach HWASan odpowiadają instrukcji, która wykonała nieprawidłowy dostęp do pamięci. Po tym zrzucie się kolejny zrzut rejestru z normalnego modułu obsługi sygnałów Androida. Zignoruj drugi zrzut, ponieważ został wykonany, gdy HWASan wywołał funkcję abort() i nie ma związku z błędem.

Symbolizacja

Aby uzyskać nazwy funkcji i numery wierszy w wyświetleniach stosu (oraz nazwy zmiennych w celu wykrywania błędów związanych z użyciem poza zakresem), konieczny jest krok symbolizacji offline.

Pierwsza konfiguracja: zainstaluj llvm-symbolizer

Aby to zilustrować, musisz mieć zainstalowany system llvm-symbolizer i mieć do niego dostęp z poziomu $PATH. W Debianie możesz go zainstalować za pomocą sudo apt install llvm.

Pobieranie plików symboli

Do symbolizacji potrzebujemy binarnych plików z symbolami, które nie zostały pozbawione niepotrzebnych danych. Ich lokalizacja zależy od typu kompilacji:

  • W przypadku kompilacji lokalnych pliki symboli znajdują się w katalogu out/target/product/<product>/symbols/.
  • W przypadku kompilacji AOSP (np. za pomocą narzędzia Android Flash Tool) kompilacje są dostępne w Android CI. W elementach kompilacji znajduje się plik ${PRODUCT}-symbols-${BUILDID}.zip.
  • W przypadku wersji wewnętrznych z Twojej organizacji zapoznaj się z dokumentacją organizacji, aby uzyskać pomoc w pobieraniu plików symboli.

Symbolize

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

Interpretowanie raportów stosu

W przypadku błędów występujących w przypadku zmiennych stosu raport HWASan zawiera takie informacje:

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)
  [...]

Aby ułatwić Ci analizowanie błędów stosu, HWASan śledzi poprzednie ramki stosu. HWASan nie przekształca ich w zrozumiałe dla człowieka treści w raporcie o błędzie i wymaga dodatkowego etapu symbolizacji.

Naruszenia zasad ODR

Niektóre błędy związane z możliwością korzystania z usługi po wygaśnięciu subskrypcji zgłoszone przez HWASan mogą wskazywać na naruszenie zasady jednej definicji (ODR). Naruszenie zasad dotyczących reklam na potrzeby pozyskiwania danych o użytkownikach ma miejsce, gdy ta sama zmienna jest zdefiniowana wielokrotnie w tym samym programie. Oznacza to też, że zmienna jest dekonstruowana wielokrotnie, co może prowadzić do błędu użycia po zwolnieniu.

Po symbolizacji naruszenia zasad ODR wskazują na błąd „use-after-free” z __cxa_finalize, zarówno w nieprawidłowym dostępie do stosu, jak i w stosie freed here. Zaalokowana wcześniej tablica zawiera zmienną __dl__ZN6soinfo17call_constructorsEv i powinna wskazywać miejsce w programie, w którym zdefiniowano zmienną wyżej w strukturze stosu.

Jeśli używasz bibliotek statycznych, możesz naruszyć zasady dotyczące ODR. Jeśli biblioteka statyczna, która definiuje zmienną globalną C++, jest połączona z wieloma bibliotekami współdzielczymi lub plikami wykonywalnymi, w tym samym zakresie adresów może istnieć wiele definicji tego samego symbolu, co powoduje błąd ODR.

Rozwiązywanie problemów

W tej sekcji opisujemy niektóre błędy i sposoby ich naprawiania.

HWAddressSanitizer nie może dokładniej opisać adresu

Czasami HWASan może zabraknąć miejsca na informacje o poprzednich przydziałach pamięci. W takim przypadku raport zawiera tylko jeden zrzut stosu dla bezpośredniego dostępu do pamięci, po którym następuje uwaga:

HWAddressSanitizer can not describe address in more detail.

W niektórych przypadkach możesz rozwiązać ten problem, wykonując test kilka razy. Inną opcją jest zwiększenie rozmiaru historii HWAS. Możesz to zrobić globalnie w build/soong/cc/sanitize.go (szukaj hwasanGlobalOptions) lub w środowisku procesu (spróbuj adb shell echo $HWASAN_OPTIONS, aby wyświetlić bieżące ustawienia).

Ten błąd może też wystąpić, jeśli dostęp do pamięci nie jest mapowany lub jest przydzielany przez alokator, który nie jest świadomy HWAS. W takim przypadku tag mem podany w nagłówku błędu jest zazwyczaj określony jako 00. Jeśli masz dostęp do pełnego nagrobka, warto skorzystać z pliku z pamięcią map, aby dowiedzieć się, do którego mapowania (jeśli takie istnieje) należy adres.

Zagnieżdżony błąd w tym samym wątku

Oznacza to, że podczas generowania raportu o wypadku HWAS wystąpił błąd. Zwykle jest to spowodowane błędem w czasie wykonywania HWASan. Zgłoś błąd i w miarę możliwości podaj instrukcje odtwarzania problemu.