Scudo to dynamiczny alokator pamięci w trybie użytkownika, czyli alokator sterty , zaprojektowany tak, aby był odporny na luki związane ze stertą (takie jak przepełnienie bufora opartego na stercie , użycie po free i double free ) przy jednoczesnym zachowaniu wydajności. Zapewnia standardowe operacje podstawowe alokacji i dezalokacji w języku C (takie jak malloc i free), a także operacje 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) .
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 bibliotecznych, a proces zostaje przerwany, jeśli na stercie wykryte zostanie uszkodzenie lub podejrzane zachowanie.
Scudo jest oprogramowaniem typu open source i częścią projektu kompilatora-rt firmy LLVM. Dokumentacja jest dostępna pod adresem https://llvm.org/docs/ScudoHardenedAllocator.html . Środowisko wykonawcze Scudo jest dostarczane jako część zestawu narzędzi Androida, a do Soong i Make dodano obsługę, aby umożliwić łatwe włączenie alokatora w formacie 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 każdego procesu na kilka sposobów:
- Statycznie: Zdefiniuj funkcję
__scudo_default_options
w programie, która zwraca ciąg opcji do przeanalizowania. Funkcja ta 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, który ma zostać przeanalizowany. Opcje zdefiniowane w ten sposób zastępują każdą definicję dokonaną za pomocą__scudo_default_options
.
Dostępne są następujące opcje.
Opcja | Domyślna wersja 64-bitowa | Domyślnie 32-bitowy | Opis |
---|---|---|---|
QuarantineSizeKb | 256 | 64 | Rozmiar (w KB) kwarantanny używany do opóźnienia faktycznego cofnięcia alokacji fragmentów. Niższa wartość może zmniejszyć użycie pamięci, ale zmniejszyć skuteczność ograniczenia; wartość ujemna powraca do wartości domyślnych. Ustawienie zarówno this, jak i ThreadLocalQuarantineSizeKb na zero całkowicie wyłącza kwarantannę. |
QuarantineChunksUpToSize | 2048 | 512 | Rozmiar (w bajtach), do jakiego fragmenty mogą być 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ę w globalnej kwarantannie. Ustawienie zarówno tej, jak i QuarantineSizeKb na zero całkowicie wyłącza kwarantannę. |
DeallocationTypeMismatch | false | false | Włącza raportowanie błędów w malloc/delete, new/free, new/delete[] |
DeleteSizeMismatch | true | true | Umożliwia raportowanie błędów w przypadku niedopasowania rozmiarów nowych i usuwanych. |
ZeroContents | false | false | Włącza zawartość porcji zerowej podczas alokacji i dezalokacji. |
allocator_may_return_null | false | false | Określa, że alokator może zwrócić wartość null w przypadku wystąpienia błędu, który można naprawić, zamiast przerywać proces. |
hard_rss_limit_mb | 0 | 0 | Kiedy RSS procesu osiągnie ten limit, proces się kończy. |
soft_rss_limit_mb | 0 | 0 | Kiedy kanał 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 kanał RSS nie zostanie ponownie wyłączony, aby umożliwić nowe alokacje. |
allocator_release_to_os_interval_ms | Nie dotyczy | 5000 | Dotyczy tylko 64-bitowego alokatora. Jeśli jest ustawione, 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 dla systemu operacyjnego. |
abort_on_error | true | true | Jeśli jest ustawione, 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 przeszły pomyślnie z włączoną funkcją Scudo lub bez niej dla danego pliku binarnego, aby sprawdzić, czy nie ma to wpływu na urządzenie.
Rozwiązywanie problemów
Jeśli zostanie wykryty problem niemożliwy do naprawienia, alokator wyświetla komunikat o błędzie w standardowym deskryptorze błędu, a następnie kończy proces. Ślady stosu prowadzące 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 bieżących komunikatów o błędach i ich potencjalnych przyczyn:
-
corrupted chunk header
: Weryfikacja sumy kontrolnej nagłówka fragmentu nie powiodła się. Dzieje się tak prawdopodobnie z dwóch powodów: 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ą jednocześnie manipulować tym samym nagłówkiem. Zwykle jest to symptomem wyścigu lub ogólnego braku blokowania podczas wykonywania operacji na tym fragmencie. -
invalid chunk state
: fragment nie znajduje się w stanie oczekiwanym dla danej operacji, na przykład nie jest przydzielany przy próbie jego zwolnienia lub nie jest poddawany kwarantannie podczas próby jego recyklingu. Podwójne wolne jest typową przyczyną tego błędu. -
misaligned pointer
: Podstawowe wymagania dotyczące wyrównania są silnie 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 tych funkcji, wskaźnik przekazany do jednej z funkcji nie jest wyrównany. -
allocation type mismatch
: gdy ta opcja jest włączona, funkcja dezalokacji wywołana dla porcji musi odpowiadać typowi funkcji, która została wywołana w celu jej alokacji. Tego typu niedopasowanie może powodować problemy z bezpieczeństwem. -
invalid sized delete
: Gdy używany jest operator usuwania rozmiaru C++ 14 i włączone jest opcjonalne sprawdzanie, występuje niezgodność między rozmiarem przekazanym podczas cofania alokacji fragmentu a rozmiarem żądanym podczas jego alokacji. Jest to zazwyczaj problem z kompilatorem lub pomyłka dotycząca typu zwalnianego obiektu. -
RSS limit exhausted
: Przekroczono opcjonalnie określoną maksymalną wartość RSS.
Jeśli debugujesz awarię w samym systemie operacyjnym, możesz użyć kompilacji HWASan OS . Jeśli debugujesz awarię w aplikacji, możesz także użyć kompilacji aplikacji HWASan .