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 .