Scudo

Scudo to dynamiczny przydziałca pamięci w trybie użytkownika, czyli przydziałca stosu, który ma być odporny na luki związane ze stosem (takie jak przepełnienie bufora w stosie, użycie po zwalnieniupodwójne zwolnienie), przy jednoczesnym zachowaniu wydajności. Zawiera standardowe prymitywy alokacji i dealokwacji języka C (takie jak malloc i free), a także prymitywy C++ (takie jak new i delete).

Scudo to raczej środek zapobiegawczy niż w pełni funkcjonalny wykrywacz błędów pamięci, taki jak AddressSanitizer (ASan).

Od wersji 11 Androida do wszystkich natywnych kodów używany jest scudo (z wyjątkiem urządzeń o małej ilości pamięci, na których nadal używany jest jemalloc). W czasie działania wszystkie natywne alokacje stosu i alokacje umów są obsługiwane przez Scudo na potrzeby wszystkich plików wykonywalnych i ich zależności bibliotek. Proces jest przerywany w przypadku wykrycia uszkodzenia lub podejrzanego działania w stercie.

Scudo to usługa open source i część projektu Compr-rt firmy LLVM. Dokumentację znajdziesz na stronie https://llvm.org/docs/ScudoHardenedAllocator.html. Środowisko wykonawcze Scudo jest dostarczane w ramach zestawu narzędzi Androida, a obsługa została dodana do Soong i Make, aby umożliwić łatwe włączenie alokatora w plikach binarnych.

Możesz włączyć lub wyłączyć dodatkowe środki zaradcze w ramach alokatora, korzystając z opcji opisanych poniżej.

Dostosowywanie

Niektóre parametry modułu alokacji można definiować oddzielnie dla każdego procesu na kilka sposobów:

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

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

Option Domyślna wersja 64-bitowa Domyślnie 32-bitowy Opis
QuarantineSizeKb 256 64 Rozmiar (w KB) kwarantanny używany do opóźnienia rzeczywistej lokalizacji umów dla fragmentów. Niższa wartość może zmniejszyć użycie pamięci, ale może też zmniejszyć skuteczność środków zaradczych. Wartość ujemna powoduje zastosowanie wartości domyślnych. Ustawienie wartości obu tych parametrów na 0 pozwala całkowicie wyłączyć kwarantannę.ThreadLocalQuarantineSizeKb
QuarantineChunksUpToSize 2048 512 Rozmiar (w bajtach), do którego można odizolować fragmenty.
ThreadLocalQuarantineSizeKb 64 16 Rozmiar (w KB) pamięci podręcznej na potrzeby poszczególnych wątków, która służy do odciążenia globalnej kwarantanny. Niższa wartość może zmniejszyć wykorzystanie pamięci, ale może zwiększyć współzawodnictwo w globalnej kwarantannie. Ustawienie wartości obu tych parametrów na 0 pozwala całkowicie wyłączyć kwarantannę.QuarantineSizeKb
DeallocationTypeMismatch false false Umożliwia zgłaszanie błędów w przypadku malloc/delete, new/free, new/delete[].
DeleteSizeMismatch true true Umożliwia raportowanie błędów w przypadku niezgodności między rozmiarami nowych i usuwanych elementów.
ZeroContents false false Umożliwia przydzielanie i odbieranie udziałów w ramach zerowych bloków treści.
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 kończyć proces.
hard_rss_limit_mb 0 0 Gdy RSS procesu osiągnie ten limit, proces zostanie zakończony.
soft_rss_limit_mb 0 0 Gdy RSS procesu osiągnie ten limit, kolejne alokacje nie będą się udawać lub będą zwracać wartość null (w zależności od wartości parametru allocator_may_return_null), dopóki RSS nie spadnie do wartości umożliwiającej nowe alokacje.
allocator_release_to_os_interval_ms Nie dotyczy 5000 Dotyczy tylko 64-bitowego przydzielacza. Jeśli jest ustawiony, próbuje zwolnić niewykorzystywaną pamięć w systemie operacyjnym, ale nie częściej niż ten interwał (w milisekundach). Jeśli wartość jest ujemna, pamięć nie jest udostępniana do systemu operacyjnego.
abort_on_error true true Jeśli jest ustawiona, narzędzie wywołuje funkcję abort() zamiast _exit() po wydrukowaniu komunikatu o błędzie.

Weryfikacja

Obecnie nie ma testów CTS przeznaczonych specjalnie dla Scudo. Zamiast tego sprawdź, czy testy CTS przechodzą z włączonym lub wyłączonym Scudo w przypadku danego pliku binarnego, aby upewnić się, że nie ma to wpływu na urządzenie.

Rozwiązywanie problemów

Jeśli zostanie wykryty problem, którego nie da się naprawić, przydzielnik wyświetli komunikat o błędzie w standardowym deskryptorze błędów, a następnie zakończy proces. Ścieżki stosu prowadzące do zakończenia są dodawane do dziennika systemowego. Wyjście zwykle zaczyna się od Scudo ERROR:, a następuje po nim krótkie podsumowanie problemu wraz ze wskazówkami.

Oto lista obecnych komunikatów o błędach i ich potencjalnych przyczynach:

  • corrupted chunk header: weryfikacja sumy kontrolnej nagłówka fragmentu się nie powiodła. Przyczyną może być jedno z tych zdarzeń: nagłówek został zastąpiony (częściowo lub całkowicie) lub wskaźnik przekazany do funkcji nie jest fragmentem.
  • race on chunk header: 2 różne wątki próbują jednocześnie manipulować tym samym nagłówkiem. Jest to zwykle objaw warunku wyścigu lub ogólnego braku blokowania podczas wykonywania operacji na tym fragmencie.
  • invalid chunk state: fragment nie ma oczekiwanego stanu w przypadku danej operacji, np. nie jest przypisany, gdy próbujesz go zwolnić, lub nie jest odizolowany, gdy próbujesz go wykorzystać. Ten błąd jest zwykle spowodowany dwukrotnym zwolnieniem pamięci.
  • misaligned pointer: są rygorystycznie egzekwowane 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 tych, wskaźnik przekazany do jednej z funkcji jest nieprawidłowo wyrównany.
  • allocation type mismatch: gdy ta opcja jest włączona, funkcja dealokacji wywołana w przypadku fragmentu musi odpowiadać funkcji wywołanej w celu alokacji. Takie niezgodności mogą powodować problemy z bezpieczeństwem.
  • invalid sized delete: jeśli używany jest operator usuwania rozmiaru C++14, a opcjonalna kontrola jest włączona, występuje niezgodność między rozmiarem, który został przekazany podczas alokacji fragmentu, a rozmiarem zażądanym podczas jego przydzielania. Zwykle jest to problem z kompilatorem lub pomylone typy obiektu, który jest przydzielany.
  • RSS limit exhausted: przekroczono opcjonalnie określony maksymalny kanał RSS.

Jeśli debugujesz awarię w samym systemie operacyjnym, możesz użyć kompilacji HWASan. Jeśli debugujesz awarię aplikacji, możesz też użyć kompilacji aplikacji HWASan.