Informacje o tym, jak odczytywać raporty o awariach HWASan, znajdziesz w artykule Interpretowanie raportów HWASan.
Sprzętowy AddressSanitizer (HWASan) to narzędzie do wykrywania błędów pamięci podobne do AddressSanitizera. HWASan wykorzystuje znacznie mniej pamięci RAM niż ASan, dzięki czemu nadaje się do czyszczenia całego systemu. HWASan jest dostępny tylko na Androidzie 10 lub nowszym i tylko na sprzęcie AArch64.
HWASan jest przydatny głównie w przypadku kodu C/C++, ale może też pomóc w debugowaniu kodu Java, który powoduje awarie w C/C++ używanym do implementowania interfejsów Java. Jest to przydatne, ponieważ wykrywa błędy pamięci, gdy się pojawią, i wskazuje bezpośrednio kod, który je spowodował.
W porównaniu z klasycznym ASan HWASan ma:
- Podobny narzut na procesor (ok. 2x)
- Podobny narzut na rozmiar kodu (40–50%)
- Znacznie mniejszy narzut pamięci RAM (10–35%)
HWASan wykrywa ten sam zestaw błędów co ASan:
- Przepełnienie lub niedopełnienie bufora stosu i sterty
- Użycie sterty po zwolnieniu
- Użycie stosu poza zakresem
- Podwójny bezpłatny/dziki bezpłatny
HWASan wykrywa też użycie stosu po powrocie.
HWASan (tak samo jak ASan) jest zgodny z UBSan. Oba te narzędzia można włączyć na urządzeniu docelowym jednocześnie.
Szczegóły implementacji i ograniczenia
HWASan opiera się na podejściu tagowania pamięci, w którym mała losowa wartość tagu jest powiązana zarówno ze wskaźnikami, jak i z zakresami adresów pamięci. Aby dostęp do pamięci był prawidłowy, tagi wskaźnika i pamięci muszą być zgodne. HWASan korzysta z funkcji ARMv8 top byte ignore (TBI), zwanej też tagowaniem adresów wirtualnych, aby przechowywać tag wskaźnika w najwyższych bitach adresu.
Więcej informacji o architekturze HWASan znajdziesz w dokumentacji Clang.
HWASan nie ma z założenia stref ochronnych o ograniczonej wielkości, które są używane przez ASan do wykrywania przepełnień, ani kwarantanny o ograniczonej pojemności, która jest używana przez ASan do wykrywania użycia po zwolnieniu. Dlatego HWASan może wykryć błąd niezależnie od tego, jak duże jest przepełnienie lub jak dawno pamięć została zwolniona. Daje to HWASan dużą przewagę nad ASan.
HWASan ma jednak ograniczoną liczbę możliwych wartości tagów (256), co oznacza, że podczas jednego wykonania programu istnieje 0,4% prawdopodobieństwo pominięcia błędu.
Wymagania
Najnowsze wersje (4.14+) wspólnego jądra Androida obsługują HWASan od razu po zainstalowaniu. Gałęzie specyficzne dla Androida 10 nie obsługują HWASan.
Obsługa HWASan w przestrzeni użytkownika jest dostępna od Androida 11.
Jeśli używasz innego jądra, HWASan wymaga, aby jądro systemu Linux akceptowało oznaczone wskaźniki w argumentach wywołań systemowych. Obsługa tej funkcji została zaimplementowana w tych zestawach poprawek:
- Interfejs ABI adresów oznaczonych tagami arm64
- arm64: untag user pointers passed to the kernel
- mm: unikaj tworzenia aliasów adresów wirtualnych w funkcjach brk()/mmap()/mremap()
- arm64: weryfikowanie oznaczonych adresów w funkcji access_ok() wywoływanej z wątków jądra
Jeśli tworzysz kompilator za pomocą niestandardowego łańcucha narzędzi, upewnij się, że zawiera on wszystkie elementy aż do commitu LLVM c336557f.
Używanie HWASan
Aby skompilować całą platformę za pomocą HWASan, użyj tych poleceń:
lunch aosp_walleye-userdebug # (or any other product)
export SANITIZE_TARGET=hwaddress
m -j
Dla wygody możesz dodać ustawienie SANITIZE_TARGET do definicji produktu, podobnie jak w przypadku aosp_coral_hwasan.
Użytkownicy, którzy znają AddressSanitizer, nie muszą się już martwić o wiele kwestii związanych ze złożonością kompilacji:
- Nie musisz uruchamiać polecenia make dwa razy.
- Kompilacje przyrostowe działają od razu.
- Nie musisz flashować danych użytkownika.
Zniknęły też niektóre ograniczenia AddressSanitizera:
- Obsługiwane są statyczne pliki wykonywalne.
- Możesz pominąć czyszczenie dowolnego miejsca docelowego innego niż libc. W przeciwieństwie do ASan nie ma wymogu, aby w przypadku oczyszczenia biblioteki oczyszczony musiał być też każdy plik wykonywalny, który ją łączy.
Przełączanie się między HWASan a zwykłymi obrazami przy tym samym (lub wyższym) numerze kompilacji jest możliwe bez ograniczeń. Nie musisz czyścić urządzenia.
Aby pominąć czyszczenie modułu, użyj LOCAL_NOSANITIZE := hwaddress
(Android.mk) lub sanitize: { hwaddress: false }
(Android.bp).
Czyszczenie poszczególnych miejsc docelowych
HWASan można włączyć dla każdego elementu docelowego w zwykłej (nieoczyszczonej) kompilacji, o ile libc.so
jest również oczyszczony. Dodaj hwaddress: true
do bloku sanitize w "libc_defaults"
w bionic/libc/Android.bp. Następnie zrób to samo w środowisku docelowym, nad którym pracujesz.
Pamiętaj, że oczyszczanie biblioteki libc umożliwia tagowanie alokacji pamięci sterty w całym systemie, a także sprawdzanie tagów pod kątem operacji na pamięci w libc.so
. Może to wykrywać błędy nawet w plikach binarnych, w których nie włączono HWASan, jeśli nieprawidłowy dostęp do pamięci występuje w libc.so
(np. pthread_mutex_unlock()
na delete()
ed mutex).
Jeśli cała platforma jest zbudowana przy użyciu HWASan, nie musisz zmieniać żadnych plików kompilacji.
Lepsze zrzuty stosu
HWASan używa szybkiego, opartego na wskaźniku ramki mechanizmu rozwijania stosu, aby rejestrować ślad stosu dla każdego zdarzenia przydzielenia i zwolnienia pamięci w programie. Android domyślnie włącza wskaźniki ramek w kodzie AArch64, więc w praktyce działa to bardzo dobrze. Jeśli chcesz cofnąć działanie kodu zarządzanego, ustaw HWASAN_OPTIONS=fast_unwind_on_malloc=0
w środowisku procesu. Pamiętaj, że ślady złego dostępu do pamięci
domyślnie korzystają z „wolnego” modułu rozwijania stosu. To ustawienie ma wpływ tylko na ślady
alokacji i dealokacji. Ta opcja może być bardzo wymagająca dla procesora w zależności od obciążenia.
Symbolizacja
Więcej informacji znajdziesz w sekcji Symbolizacja w artykule „Interpretowanie raportów HWASan”.
HWASan w aplikacjach
Podobnie jak AddressSanitizer, HWASan nie widzi kodu Java, ale może wykrywać błędy w bibliotekach JNI. Do Androida 14 uruchamianie aplikacji HWASan na urządzeniu bez HWASan było nie obsługiwane.
Na urządzeniu z HWASan aplikacje można sprawdzić za pomocą HWASan, kompilując ich kod za pomocą SANITIZE_TARGET:=hwaddress
w Make lub -fsanitize=hwaddress
we flagach kompilatora.
Na urządzeniu bez HWASan (z Androidem 14 lub nowszym) należy dodać ustawienie pliku wrap.sh:LD_HWASAN=1
Więcej informacji znajdziesz w dokumentacji dla deweloperów aplikacji.