AddressSanitizer (ASan) to szybkie narzędzie oparte na kompilatorze, które wykrywa błędy pamięci w kodzie natywnym.
ASan wykrywa:
- Przepełnienie/niedopełnienie bufora stosu i bufora stosu.
- Wykorzystanie sterty po bezpłatnym
- Użycie zasobów spoza zakresu
- Podwójny wolny/szlachetny
ASan działa w architekturze 32- i 64-bitowej ARM oraz architekturze x86 i x86-64. Narzut na procesor w ASan wynosi około 2 razy, narzut na rozmiar kodu – od 50% do 2 razy, a narzut na pamięć – około 2 razy (zależy od wzorca alokacji).
Android 10 i główna gałąź AOSP w AArch64 obsługuje sprzętowy serwer AddressSanitizer (HWASan). podobnego narzędzia z mniejszym nadmiarem pamięci RAM i większym wykrywanych błędów. Oprócz błędów HWASan wykrywa też użycie stosu po powrocie wykryte przez ASan.
HWASan ma podobny narzut na procesor i rozmiar kodu, ale znacznie mniejszy narzut na pamięć RAM (15%). HWASan nie jest deterministyczny. Istnieje tylko 256 możliwych wartości tagów, więc prawdopodobieństwo przeoczenia błędu wynosi 0,4%. HWASan nie ma stref czerwonych o ograniczonej wielkości, które służą do wykrywania przepełnienia, ani stref kwarantanny o ograniczonej pojemności, które służą do wykrywania użycia po zwolnieniu, więc nie ma znaczenia, jak duże jest przepełnienie ani jak dawno przydzielone było pamięci. Dzięki temu HWASan jest lepszy niż ASan. Więcej informacji na ten temat znajdziesz projekt HWASan lub informacje o korzystaniu z HWASan na Androidzie.
ASan wykrywa nadmiarowe treści stosu/globalne nie tylko przepełnia się stertą, ale też jest szybka i przy minimalnym nadmiarze pamięci.
W tym dokumencie opisujemy, jak stworzyć i uruchomić części/całość Androida ASan. Jeśli tworzysz aplikację na podstawie pakietu SDK lub NDK z użyciem ASan, zapoznaj się z artykułem Address Sanitizer.
Czyszczenie poszczególnych plików wykonywalnych za pomocą ASan
Dodaj LOCAL_SANITIZE:=address
lub sanitize: { address: true }
do reguły kompilacji pliku wykonywalnego. Możesz wyszukać w kodzie istniejące przykłady lub znaleźć
inne dostępne środki dezynfekcyjne.
Gdy zostanie wykryty błąd, ASan wypisuje obszerny raport zarówno do standardowego wyjścia, jak i do pliku logcat
, a potem powoduje awarię procesu.
Czyszczenie bibliotek udostępnionych za pomocą ASan
Ze względu na sposób działania ASan z biblioteki utworzonej przy użyciu tego języka może korzystać tylko który został utworzony w ASan.
Aby odizolować wspólną bibliotekę, która jest używana w kilku plikach wykonywalnych, ale nie wszystkie z nich są skompilowane za pomocą ASan, potrzebujesz 2 kopii biblioteki.
Zalecany sposób to dodanie do Android.mk
w odpowiednim module:
LOCAL_SANITIZE:=address LOCAL_MODULE_RELATIVE_PATH := asan
Spowoduje to przeniesienie biblioteki do języka /system/lib/asan
, a nie
/system/lib
Następnie uruchom plik wykonywalny:
LD_LIBRARY_PATH=/system/lib/asan
W przypadku demonów systemowych dodaj poniższy kod do odpowiedniej sekcji
/init.rc
lub /init.$device$.rc
.
setenv LD_LIBRARY_PATH /system/lib/asan
Sprawdź, czy proces używa bibliotek z /system/lib/asan
gdy jest dostępny, odczytując treść /proc/$PID/maps
. Jeśli nie, być może trzeba wyłączyć SELinux:
adb root
adb shell setenforce 0
# restart the process with adb shell kill $PID # if it is a system service, or may be adb shell stop; adb shell start.
Lepsze zrzuty stosu
ASan używa szybkiego odwijacza opartego na wskaźniku ramki, aby zapisywać informacje o ścieżce wywołań dla każdego zdarzenia przydzielenia i zwolnienia pamięci w programie. Większość aplikacji na Androida bez wskaźników klatek. W rezultacie często otrzymujesz tylko jedną lub dwie znaczące klatki. Aby rozwiązać ten problem, odbuduj bibliotekę przy użyciu ASan (zalecane) lub:
LOCAL_CFLAGS:=-fno-omit-frame-pointer LOCAL_ARM_MODE:=arm
Możesz też ustawić parametr ASAN_OPTIONS=fast_unwind_on_malloc=0
w środowisku procesu. Ten drugi tryb może znacznie obciążać procesor.
i zwiększania obciążenia.
Symbole
Początkowo raporty ASan zawierają odniesienia do przesunięcia w plikach binarnych i udostępnione biblioteki. Informacje o pliku źródłowym i liniach możesz uzyskać na 2 sposoby:
- Sprawdź, czy w pliku
/system/bin
znajduje się plik binarnyllvm-symbolizer
.llvm-symbolizer
jest tworzony na podstawie źródeł wthird_party/llvm/tools/llvm-symbolizer
. - Przefiltruj raport według tych danych:
external/compiler-rt/lib/asan/scripts/symbolize.py
skrypt.
Drugie podejście może dostarczyć więcej danych (czyli file:line
lokalizacji) ze względu na dostępność bibliotek symboli na hoście.
ASan w aplikacjach
ASan nie widzi kodu Java, ale może wykryć błędy w JNI
biblioteki. W tym celu musisz skompilować plik wykonywalny za pomocą ASan, który w tym przypadku to /system/bin/app_process(32|64)
. Ten
włącza ASan we wszystkich aplikacjach na urządzeniu jednocześnie, co jest
duże obciążenie, ale urządzenie z 2 GB pamięci RAM powinno to dać.
Dodaj LOCAL_SANITIZE:=address
do reguły kompilacji app_process
w frameworks/base/cmds/app_process
. Na razie zignoruj obiekt app_process__asan
w tym samym pliku (jeśli jest on nadal obecny w momencie, gdy czytasz ten artykuł).
Edytuj sekcję service zygote
odpowiedni plik system/core/rootdir/init.zygote(32|64).rc
, by dodać
kolejnych wierszy do bloku z wcięciem zawierającego class main
, a także
z wcięciem o taką samą kwotę:
setenv LD_LIBRARY_PATH /system/lib/asan:/system/lib setenv ASAN_OPTIONS allow_user_segv_handler=true
Kompilacja, synchronizacja adb, uruchamianie Flasha typu fastboot i ponowne uruchamianie.
Używanie właściwości zawijania
Podejście z poprzedniej sekcji uwzględnia ASan w każdym aplikacji w systemie (a dokładnie do każdego elementu potomnego Zygote), ). Z ASan można uruchomić tylko jedną (lub kilka) aplikacji, i wyjątkiem pamięci, aby wolniej uruchamiać aplikacje.
Aby to zrobić, uruchom aplikację za pomocą właściwości wrap.
.
Poniższy przykład uruchamia aplikację Gmail pod ASan:
adb root
adb shell setenforce 0 # disable SELinux
adb shell setprop wrap.com.google.android.gm "asanwrapper"
W tym kontekście usługa asanwrapper
zastępuje usługę /system/bin/app_process
usługą /system/bin/asan/app_process
, która została utworzona za pomocą ASANA. Dodaje też /system/lib/asan
na początku ścieżki wyszukiwania dynamicznej biblioteki. W ten sposób biblioteki z /system/lib/asan
z instrumentacją ASan są preferowane w odróżnieniu od zwykłych bibliotek w /system/lib
podczas uruchamiania z asanwrapper
.
W przypadku znalezienia błędu aplikacja ulega awarii, a raport jest drukowany dziennika.
SANITIZE_TARGET
Android 7.0 i nowsze wersje obsługują kompilowanie całej platformy Androida za pomocą ASANA. (jeśli tworzysz wersję w wersji nowszej niż Androida 9, lepszym rozwiązaniem będzie HWASan).
Uruchom podane niżej polecenia w tym samym drzewie kompilacji.
make -j42
SANITIZE_TARGET=address make -j42
W tym trybie userdata.img
zawiera dodatkowe biblioteki i musi zostać wgrany na urządzenie. Użyj tego wiersza poleceń:
fastboot flash userdata && fastboot flashall
Spowoduje to utworzenie 2 zestawów bibliotek wspólnych: normalnej w /system/lib
(pierwsze wywołanie make) i z instrumentacją ASan w /data/asan/lib
(drugie wywołanie make). Pliki wykonywalne z drugiej kompilacji zastąpią te z pierwszej. Z systemem ASan
pliki wykonywalne otrzymują inną ścieżkę wyszukiwania biblioteki zawierającą
/data/asan/lib
przed /system/lib
za pomocą
/system/bin/linker_asan
w: PT_INTERP
.
System kompilacji blokuje pośrednie katalogi obiektów, gdy
Wartość $SANITIZE_TARGET
uległa zmianie. Zmusza to do odbudowy
docelowe przy jednoczesnym zachowaniu zainstalowanych plików binarnych na poziomie /system/lib
.
Niektórych celów nie można tworzyć za pomocą ASan:
- Statyczni pliki wykonywalne
LOCAL_CLANG:=false
celLOCAL_SANITIZE:=false
nie jest sygnalizowany przez:SANITIZE_TARGET=address
Pliki wykonywalne takie jak te są pomijane w kompilacji SANITIZE_TARGET
, a parametry
w /system/bin
pozostanie wersja z pierwszego wywołania marki.
Biblioteki takie jak ta są tworzone bez ASan. Mogą zawierać niektóre elementy ASan. z bibliotek statycznych, na których bazują.