Debugowanie i eliminowanie błędów pamięci

Android obsługuje wiele narzędzi do debugowania błędów pamięci. Każda z nich ma swoje zalety. Zapoznaj się z poniższymi wskazówkami, aby zdecydować, która z nich będzie najlepsza w Twoim przypadku. Ten dokument zawiera przegląd dostępnych narzędzi, co pozwala Ci podjąć decyzję o tym, które z nich warto zbadać. Jest on jednak zwięzły. Więcej informacji znajdziesz w dokumentacji poszczególnych narzędzi.

TL;DR

  • Aby uniknąć błędów pamięci, w miarę możliwości używaj języka bezpiecznego dla pamięci.
  • Zawsze używaj PAC/BTI do łagodzenia ataków ROP/JOP
  • Zawsze używaj GWP-ASan do wykrywania rzadkich błędów pamięci w środowisku produkcyjnym
  • Używanie HWASan do wykrywania błędów pamięci podczas testowania
  • Urządzenia obsługujące MTE nie są ogólnie dostępne w 2023 r., ale warto z nich korzystać, jeśli wykrywasz błędy w środowisku produkcyjnym
  • Używaj ASan podczas testowania tylko w ostateczności

Języki, w których dostępna jest pamięć

Użycie języka bezpiecznego dla pamięci to jedyny sposób, aby całkowicie uniknąć błędów związanych z pamięcią i ograniczyć ich skutki. Inne narzędzia na tej stronie mogą pomóc zwiększyć bezpieczeństwo i niezawodność kodu pamięci. Jednak użycie języka bezpiecznego dla pamięci eliminuje całą grupę problemów.

Oficjalnie obsługiwanymi językami bezpieczeństwa pamięci na Androidzie są Java i Kotlin. Większość aplikacji na Androida jest łatwiejsza w tworzeniu w jednym z tych języków.

Pamiętaj, że kod wysyłki dla deweloperów aplikacji jest napisany w Rust. Jeśli czytasz tę stronę, prawdopodobnie masz ku temu dobry powód, by potrzebować kodu natywnego (przenośność, wydajność lub jedno i drugie). Rust to najlepszy wybór w przypadku bezpiecznego dla pamięci kodu natywnego na Androida. Zespół NDK nie musi pomóc Ci z problemami, które napotkasz, jeśli się na to zdecydujesz, ale chętnie dowiemy się o nich.

PAC/BTI

Uwierzytelnianie wskaźnika oraz identyfikacja celu gałęzi (nazywane też PAC/BTI) to narzędzia do ograniczania ryzyka, odpowiednie do stosowania w środowisku produkcyjnym. Chociaż są to osobne technologie, są one kontrolowane przez tę samą flagę kompilatora, więc zawsze są używane razem.

Te funkcje są wstecznie zgodne z urządzeniami, które ich nie obsługują, ponieważ nowe instrukcje nie działają na wcześniejszych urządzeniach. Niezbędne jest również nowe jądro i wystarczająca wersja systemu operacyjnego. Wyszukiwanie paca i bti w /proc/cpuinfo pokaże Ci, czy masz wystarczająco dużo nowego sprzętu i nowe jądro. Android 12 (API 31) ma niezbędną obsługę przestrzeni użytkownika.

Zalety:

  • Można ją włączyć we wszystkich kompilacjach, nie powodując problemów na starszych urządzeniach lub jądrach (ale upewnij się, że testujesz ją na takiej kombinacji urządzenia, jądra i systemu operacyjnego, która obsługuje tę funkcję).

Wady:

  • Dostępne tylko w aplikacjach 64-bitowych
  • Nie eliminuje błędów na urządzeniach, które ich nie obsługują
  • Narzut na rozmiar kodu 1%

GWP-Asan

Do wykrywania błędów pamięci w polu można używać narzędzia GWP-ASan, ale częstotliwość próbkowania jest zbyt niska, aby skutecznie przeciwdziałać problemom.

Zalety:

  • Brak znacznego obciążenia procesora i pamięci.
  • Proste do wdrożenia: nie wymaga ponownego kompilowania kodu natywnego
  • Działa w aplikacjach 32-bitowych

Wady:

  • Niska częstotliwość próbkowania wymaga dużej liczby użytkowników, aby skutecznie znajdować błędy
  • Wykrywanie tylko błędów sterty, a nie błędów stosu

HWASan

Sprzęt do dezynfekcji adresów (HWASan) najlepiej nadaje się do wykrywania błędów pamięci podczas testowania. Jest on najbardziej przydatny w przypadku testów automatycznych, zwłaszcza gdy przeprowadzasz testy z dużą szybkością. Jednak w zależności od potrzeb w zakresie wydajności aplikacji może być też używany w wersji testowej na zaawansowanych telefonach komórkowych.

Zalety:

  • Brak wyników fałszywie pozytywnych
  • Wykrywa dodatkowe klasy błędów, których ASan nie może używać (używanie stosu po zwróceniu)
  • Niższy współczynnik wyników fałszywie negatywnych niż MTE (1 na 256 w porównaniu z 1 na 16)
  • Mniejszy zużycie pamięci niż w przypadku ASan, jego najbliższa alternatywa

Wady:

  • Znaczący (ok. 100%), rozmiar kodu (ok. 50%) i ilość pamięci (10%–35%)
  • Do interfejsów API 34 i NDK r26 wymagane jest przeprowadzenie aktualizacji obrazu zgodnego z HWASan
  • Działa tylko w aplikacjach 64-bitowych

MTE

Rozszerzenie do tagowania pamięci, znane też jako MTE, to tańsza alternatywa dla HWASan. Poza funkcjami debugowania i testowania można też używać jej do wykrywania i łagodzenia uszkodzeń pamięci w środowisku produkcyjnym. Jeśli masz sprzęt do testowania kompilacji MTE, włącz go.

Zalety:

  • Na tyle niski koszt, że będzie tolerowany w przypadku wielu aplikacji w wersji produkcyjnej
  • Brak wyników fałszywie pozytywnych
  • Nie wymaga ponownego kompilowania kodu w celu wykrywania błędów sterty (ale robi to do wykrywania błędów stosu)

Wady:

  • W 2024 r. nie ma dostępnych komercyjnie urządzeń z włączoną domyślnie obsługą MTE. Dokumentacja firmy Armer wyjaśnia, jak włączyć MTE do testów na Pixelu 8/Pixelu 8 Pro.
  • Współczynnik wyników fałszywie ujemnych 1 na 16 w porównaniu do 1 HWASan na 256
  • Dostępne tylko w aplikacjach 64-bitowych
  • Wymaga utworzenia osobnych bibliotek do kierowania zarówno na urządzenia z obsługą MTE, jak i bez niego

ASan

Narzędzie do dezynfekcji adresów (ASan) to najstarsze i najpowszechniej dostępne narzędzie. Jest on przydatny w przypadku błędów pamięci podczas testowania i debugowania problemów, które mają wpływ tylko na stare urządzenia, na których nie ma żadnych innych narzędzi. Gdy tylko jest to możliwe, wybieraj HWASan.

Zalety:

  • Powszechnie dostępne. Może działać na urządzeniach starszych niż KitKat
  • Prawidłowo używane nie są wyniki fałszywie pozytywne ani negatywne

Wady:

  • Trudności z prawidłowym stworzeniem i zapakowaniem
  • Największy narzut spośród wszystkich opcji: ok. 100% procesora, rozmiar kodu ok. 50%, wykorzystanie pamięci ok. 100%
  • Funkcja nie jest już obsługiwana
  • Zawiera znane błędy, których nie naprawimy