Scudo

Scudo to dynamiczny alokator pamięci w trybie użytkownika lub alokator sterty , zaprojektowany tak, aby był odporny na luki w zabezpieczeniach związane ze stertą (takie jak przepełnienie buforu na stercie, użycie po free i double free ) przy zachowaniu wydajności. Zapewnia standardowe operacje podstawowe alokacji i cofania alokacji języka C (takie jak malloc i free), a także elementy podstawowe C++ (takie jak new i delete).

Scudo jest bardziej środkiem łagodzącym niż pełnoprawnym wykrywaczem błędów pamięci, takim jak AddressSanitizer (ASan) .

Począwszy od wydania Androida 11, scudo jest używane dla całego kodu natywnego (z wyjątkiem urządzeń o małej ilości pamięci, gdzie nadal używany jest jemalloc). W czasie wykonywania wszystkie natywne alokacje sterty i cofnięcia alokacji są obsługiwane przez Scudo dla wszystkich plików wykonywalnych i ich zależności bibliotecznych, a proces jest przerywany, jeśli w stercie zostanie wykryte uszkodzenie lub podejrzane zachowanie.

W Androidzie 10 scudo musiało być włączone na zasadzie binarnej, ustawiając LOCAL_SANITIZE := scudo w pliku .mk lub sanitize: { scudo: true, } w pliku .bp.

Scudo jest oprogramowaniem typu open source i częścią projektu kompilatora-rt LLVM. Dokumentacja jest dostępna pod adresem https://llvm.org/docs/ScudoHardenedAllocator.html . Środowisko uruchomieniowe Scudo jest dostarczane jako część łańcucha narzędzi Androida, a wsparcie zostało dodane do Soong i Make , aby umożliwić łatwe włączanie alokatora w postaci binarnej.

Możesz włączyć lub wyłączyć dodatkowe środki łagodzące w alokatorze, korzystając z opcji opisanych poniżej.

Dostosowywanie

Niektóre parametry podzielnika można zdefiniować dla poszczególnych procesów na kilka sposobów:

  • Statycznie: Zdefiniuj funkcję __scudo_default_options w programie, która zwraca ciąg opcji do przeanalizowania. Ta funkcja musi mieć następujący prototyp: extern "C" const char *__scudo_default_options() .
  • Dynamicznie: użyj zmiennej środowiskowej SCUDO_OPTIONS zawierającej ciąg opcji do przeanalizowania. Opcje zdefiniowane w ten sposób zastępują wszelkie definicje wprowadzone przez __scudo_default_options .

Dostępne są następujące opcje.

Opcja Domyślna 64-bitowa 32-bitowa domyślna Opis
QuarantineSizeKb 256 64 Rozmiar (w KB) kwarantanny używany do opóźnienia faktycznego cofnięcia alokacji porcji. Niższa wartość może zmniejszyć użycie pamięci, ale zmniejszyć skuteczność łagodzenia; wartość ujemna wraca do wartości domyślnych. Ustawienie tego i ThreadLocalQuarantineSizeKb na zero całkowicie wyłącza kwarantannę.
QuarantineChunksUpToSize 2048 512 Rozmiar (w bajtach), do którego porcje mogą zostać poddane kwarantannie.
ThreadLocalQuarantineSizeKb 64 16 Rozmiar (w KB) pamięci podręcznej na wątek używanej do odciążenia globalnej kwarantanny. Niższa wartość może zmniejszyć użycie pamięci, ale może zwiększyć rywalizację o globalną kwarantannę. Ustawienie zarówno tego, jak i QuarantineSizeKb na zero, całkowicie wyłącza kwarantannę.
DeallocationTypeMismatch false false Włącza raportowanie błędów na malloc/usuń, nowy/wolny, nowy/usuń[]
DeleteSizeMismatch true true Włącza raportowanie błędów w przypadku niezgodności między rozmiarami nowych i usuniętych.
ZeroContents false false Włącza zerową zawartość porcji podczas alokacji i cofania alokacji.
allocator_may_return_null false false Określa, że ​​alokator może zwrócić wartość null, gdy wystąpi błąd, który można naprawić, zamiast przerywać proces.
hard_rss_limit_mb 0 0 Gdy RSS procesu osiągnie ten limit, proces zostaje zakończony.
soft_rss_limit_mb 0 0 Gdy RSS procesu osiągnie ten limit, dalsze alokacje kończą się niepowodzeniem lub zwracają null (w zależności od wartości allocator_may_return_null ), dopóki RSS nie wróci w dół, aby umożliwić nowe alokacje.
allocator_release_to_os_interval_ms nie dotyczy 5000 Dotyczy tylko alokatora 64-bitowego. Jeśli jest ustawiona, próbuje zwolnić nieużywaną pamięć do systemu operacyjnego, ale nie częściej niż ten interwał (w milisekundach). Jeśli wartość jest ujemna, pamięć nie jest zwalniana do systemu operacyjnego.
abort_on_error true true Jeśli jest ustawiona, narzędzie wywołuje abort() zamiast _exit() po wydrukowaniu komunikatu o błędzie.

Walidacja

Obecnie nie ma testów CTS specjalnie dla Scudo. Zamiast tego upewnij się, że testy CTS przechodzą z lub bez włączonej funkcji Scudo dla danego pliku binarnego, aby sprawdzić, czy nie ma to wpływu na urządzenie.

Rozwiązywanie problemów

W przypadku wykrycia problemu, którego nie można naprawić, alokator wyświetla komunikat o błędzie do standardowego deskryptora błędu, a następnie kończy proces. Ślady stosu, które prowadzą do zakończenia, są dodawane w dzienniku systemowym. Dane wyjściowe zwykle zaczynają się od Scudo ERROR: po którym następuje krótkie podsumowanie problemu wraz ze wskazówkami.

Oto lista aktualnych komunikatów o błędach i ich potencjalnych przyczyn:

  • corrupted chunk header : Weryfikacja sumy kontrolnej nagłówka porcji nie powiodła się. Jest to prawdopodobnie spowodowane jedną z dwóch rzeczy: nagłówek został nadpisany (częściowo lub całkowicie) lub wskaźnik przekazany do funkcji nie jest fragmentem.
  • race on chunk header : dwa różne wątki próbują manipulować tym samym nagłówkiem w tym samym czasie. Zwykle jest to objawem wyścigu lub ogólnego braku blokowania podczas wykonywania operacji na tym fragmencie.
  • invalid chunk state : porcja nie jest w stanie oczekiwanym dla danej operacji, na przykład nie jest przydzielona podczas próby jej zwolnienia lub nie jest poddawana kwarantannie podczas próby jej odtworzenia. Podwójna wolna jest typową przyczyną tego błędu.
  • misaligned pointer : mocno wymuszane są podstawowe wymagania dotyczące wyrównania: 8 bajtów na platformach 32-bitowych i 16 bajtów na platformach 64-bitowych. Jeśli wskaźnik przekazany do naszych funkcji nie pasuje do nich, wskaźnik przekazany do jednej z funkcji nie jest wyrównany.
  • allocation type mismatch : gdy ta opcja jest włączona, funkcja cofania alokacji wywoływana dla porcji musi być zgodna z typem funkcji, która została wywołana w celu jej alokacji. Ten rodzaj niezgodności może powodować problemy z bezpieczeństwem.
  • invalid sized delete : Gdy używany jest operator usuwania o rozmiarze C++14, a opcjonalna kontrola jest włączona, występuje niezgodność między rozmiarem, który został przekazany podczas cofania alokacji porcji, a rozmiarem żądanym podczas alokacji. Jest to zwykle problem z kompilatorem lub pomyłka typów w zwalnianym obiekcie.
  • RSS limit exhausted : Maksymalna określona opcjonalnie wartość RSS została przekroczona.

Jeśli debugujesz awarię samego systemu operacyjnego, możesz użyć kompilacji HWASan OS . Jeśli debugujesz awarię aplikacji, możesz również użyć kompilacji aplikacji HWASan .