Scudo

Scudo to dynamiczny alokator pamięci w trybie użytkownika lub alokator sterty , zaprojektowany tak, aby był odporny na luki związane ze stertą (takie jak przepełnienie bufora oparte na stercie , use after free i double free ) przy zachowaniu wydajności. Zapewnia standardowe prymitywy alokacji i zwalniania alokacji C (takie jak malloc i free), jak również prymitywy 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) .

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 i dezalokacje sterty są obsługiwane przez Scudo dla wszystkich plików wykonywalnych i ich zależności w bibliotekach, a proces jest przerywany, jeśli na stercie zostanie wykryte uszkodzenie lub podejrzane zachowanie.

Scudo jest oprogramowaniem typu open source i częścią projektu kompilator-rt firmy LLVM. Dokumentacja jest dostępna na stronie 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łączenie alokatora w pliku binarnym.

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

Dostosowywanie

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

  • Statycznie: Zdefiniuj funkcję __scudo_default_options w programie, która zwraca łańcuch 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 utworzone za pomocą __scudo_default_options .

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

Opcja Domyślnie 64-bitowy Domyślnie 32-bitowy 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 powraca do wartości domyślnych. Ustawienie zarówno tego, jak 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 dla malloc/delete, new/free, new/delete[]
DeleteSizeMismatch true true Włącza raportowanie błędów w przypadku niezgodności między rozmiarami nowych i usuwanych.
ZeroContents false false Włącza zawartość zerowej porcji podczas alokacji i cofnięcia alokacji.
allocator_may_return_null false false Określa, że ​​alokator może zwrócić wartość null, gdy wystąpi naprawialny błąd, zamiast przerywać proces.
hard_rss_limit_mb 0 0 Gdy RSS procesu osiągnie ten limit, proces kończy się.
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 spadnie, aby umożliwić nowe alokacje.
allocator_release_to_os_interval_ms Nie dotyczy 5000 Wpływa tylko na alokator 64-bitowy. Jeśli jest ustawiona, próbuje zwolnić nieużywaną pamięć dla 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 włączonym Scudo lub bez niego dla danego pliku binarnego, aby sprawdzić, czy nie ma to wpływu na urządzenie.

Rozwiązywanie problemów

W przypadku wykrycia nieodwracalnego problemu alokator wyświetla komunikat o błędzie w standardowym deskryptorze błędów, a następnie kończy proces. Ślady stosu prowadzące do zakończenia są dodawane do dziennika systemowego. Wyjście zwykle zaczyna się od Scudo ERROR: po którym następuje krótkie podsumowanie problemu wraz z wszelkimi wskazówkami.

Oto lista bieżących 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. Jest to zwykle 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 przydzielana podczas próby jej zwolnienia lub nie jest poddawana kwarantannie podczas próby ponownego wykorzystania. Typową przyczyną tego błędu jest podwójne zwolnienie.
  • misaligned pointer : podstawowe wymagania dotyczące wyrównania są mocno egzekwowane: 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łana na porcji musi być zgodna z typem funkcji, która została wywołana w celu jej alokacji. Ten typ niezgodności może powodować problemy z bezpieczeństwem.
  • invalid sized delete : Gdy używany jest operator usuwania rozmiaru języka C++ 14 i włączona jest opcjonalna kontrola, występuje niezgodność między rozmiarem, który został przekazany podczas cofania przydziału porcji, a rozmiarem żądanym podczas jej przydzielania. Zwykle jest to problem z kompilatorem lub pomyłka typu obiektu, który ma zostać cofnięty.
  • RSS limit exhausted : Przekroczono opcjonalnie określony maksymalny RSS.

Jeśli debugujesz awarię w samym systemie operacyjnym, możesz użyć kompilacji HWASan OS . Jeśli debugujesz awarię w aplikacji, możliwe jest również użycie kompilacji aplikacji HWASan .

,

Scudo to dynamiczny alokator pamięci w trybie użytkownika lub alokator sterty , zaprojektowany tak, aby był odporny na luki związane ze stertą (takie jak przepełnienie bufora oparte na stercie , use after free i double free ) przy zachowaniu wydajności. Zapewnia standardowe prymitywy alokacji i zwalniania alokacji C (takie jak malloc i free), jak również prymitywy 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) .

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 i dezalokacje sterty są obsługiwane przez Scudo dla wszystkich plików wykonywalnych i ich zależności w bibliotekach, a proces jest przerywany, jeśli na stercie zostanie wykryte uszkodzenie lub podejrzane zachowanie.

Scudo jest oprogramowaniem typu open source i częścią projektu kompilator-rt firmy LLVM. Dokumentacja jest dostępna na stronie 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łączenie alokatora w pliku binarnym.

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

Dostosowywanie

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

  • Statycznie: Zdefiniuj funkcję __scudo_default_options w programie, która zwraca łańcuch 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 utworzone za pomocą __scudo_default_options .

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

Opcja Domyślnie 64-bitowy Domyślnie 32-bitowy 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 powraca do wartości domyślnych. Ustawienie zarówno tego, jak 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 dla malloc/delete, new/free, new/delete[]
DeleteSizeMismatch true true Włącza raportowanie błędów w przypadku niezgodności między rozmiarami nowych i usuwanych.
ZeroContents false false Włącza zawartość zerowej porcji podczas alokacji i cofnięcia alokacji.
allocator_may_return_null false false Określa, że ​​alokator może zwrócić wartość null, gdy wystąpi naprawialny błąd, zamiast przerywać proces.
hard_rss_limit_mb 0 0 Gdy RSS procesu osiągnie ten limit, proces kończy się.
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 spadnie, aby umożliwić nowe alokacje.
allocator_release_to_os_interval_ms Nie dotyczy 5000 Wpływa tylko na alokator 64-bitowy. Jeśli jest ustawiona, próbuje zwolnić nieużywaną pamięć dla 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 włączonym Scudo lub bez niego dla danego pliku binarnego, aby sprawdzić, czy nie ma to wpływu na urządzenie.

Rozwiązywanie problemów

W przypadku wykrycia nieodwracalnego problemu alokator wyświetla komunikat o błędzie w standardowym deskryptorze błędów, a następnie kończy proces. Ślady stosu prowadzące do zakończenia są dodawane do dziennika systemowego. Wyjście zwykle zaczyna się od Scudo ERROR: po którym następuje krótkie podsumowanie problemu wraz z wszelkimi wskazówkami.

Oto lista bieżących 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. Jest to zwykle 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 przydzielana podczas próby jej zwolnienia lub nie jest poddawana kwarantannie podczas próby ponownego wykorzystania. Typową przyczyną tego błędu jest podwójne zwolnienie.
  • misaligned pointer : podstawowe wymagania dotyczące wyrównania są mocno egzekwowane: 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łana na porcji musi być zgodna z typem funkcji, która została wywołana w celu jej alokacji. Ten typ niezgodności może powodować problemy z bezpieczeństwem.
  • invalid sized delete : Gdy używany jest operator usuwania rozmiaru języka C++ 14 i włączona jest opcjonalna kontrola, występuje niezgodność między rozmiarem, który został przekazany podczas cofania przydziału porcji, a rozmiarem żądanym podczas jej przydzielania. Zwykle jest to problem z kompilatorem lub pomyłka typu obiektu, który ma zostać cofnięty.
  • RSS limit exhausted : Przekroczono opcjonalnie określony maksymalny RSS.

Jeśli debugujesz awarię w samym systemie operacyjnym, możesz użyć kompilacji HWASan OS . Jeśli debugujesz awarię w aplikacji, możliwe jest również użycie kompilacji aplikacji HWASan .