Scudo

Scudo ist ein dynamischer Speicherzuweiser oder Heap- Zuweiser im Benutzermodus, der so konzipiert ist, dass er gegen Schwachstellen im Zusammenhang mit dem Heap (z. B. Heap-basierter Pufferüberlauf , Verwendung nach dem Freigeben und Doppeltes Freigeben ) resistent ist und gleichzeitig die Leistung beibehält. Es stellt die standardmäßigen C-Zuweisungs- und Freigabeprimitive (z. B. malloc und free) sowie die C++-Primitive (z. B. new und delete) bereit.

Scudo ist eher eine Schadensbegrenzung als ein vollwertiger Speicherfehlerdetektor wie AddressSanitizer (ASan) .

Seit der Veröffentlichung von Android 11 wird scudo für den gesamten nativen Code verwendet (außer auf Geräten mit wenig Speicher, wo immer noch Jemalloc verwendet wird). Zur Laufzeit werden alle nativen Heap-Zuweisungen und -Freigaben von Scudo für alle ausführbaren Dateien und deren Bibliotheksabhängigkeiten durchgeführt. Der Prozess wird abgebrochen, wenn eine Beschädigung oder ein verdächtiges Verhalten im Heap erkannt wird.

Scudo ist Open Source und Teil des Compiler-RT-Projekts von LLVM. Die Dokumentation ist unter https://llvm.org/docs/ScudoHardenedAllocator.html verfügbar. Die Scudo-Laufzeit wird als Teil der Android-Toolchain geliefert und Soong und Make wurden um Unterstützung erweitert, um eine einfache Aktivierung des Allokators in einer Binärdatei zu ermöglichen.

Mit den unten beschriebenen Optionen können Sie zusätzliche Abhilfemaßnahmen innerhalb des Allokators aktivieren oder deaktivieren.

Anpassung

Einige Parameter des Allokators können auf verschiedene Weise pro Prozess definiert werden:

  • Statisch: Definieren Sie eine __scudo_default_options -Funktion im Programm, die die zu analysierende Optionszeichenfolge zurückgibt. Diese Funktion muss den folgenden Prototyp haben: extern "C" const char *__scudo_default_options() .
  • Dynamisch: Verwenden Sie die Umgebungsvariable SCUDO_OPTIONS die die zu analysierende Optionszeichenfolge enthält. Auf diese Weise definierte Optionen überschreiben alle über __scudo_default_options vorgenommenen Definitionen.

Die folgenden Optionen stehen zur Verfügung.

Möglichkeit 64-Bit-Standard 32-Bit-Standard Beschreibung
QuarantineSizeKb 256 64 Die Größe (in KB) der Quarantäne, die verwendet wird, um die tatsächliche Freigabe von Blöcken zu verzögern. Ein niedrigerer Wert verringert möglicherweise die Speichernutzung, verringert jedoch die Wirksamkeit der Schadensbegrenzung. Bei einem negativen Wert wird auf die Standardwerte zurückgegriffen. Wenn Sie sowohl dies als auch ThreadLocalQuarantineSizeKb auf Null setzen, wird die Quarantäne vollständig deaktiviert.
QuarantineChunksUpToSize 2048 512 Die Größe (in Bytes), bis zu der Chunks unter Quarantäne gestellt werden können.
ThreadLocalQuarantineSizeKb 64 16 Die Größe (in KB) des Pro-Thread-Cache, der zum Auslagern der globalen Quarantäne verwendet wird. Ein niedrigerer Wert verringert möglicherweise die Speichernutzung, erhöht jedoch möglicherweise die Konkurrenz um die globale Quarantäne. Wenn Sie sowohl diesen Wert als auch QuarantineSizeKb auf Null setzen, wird die Quarantäne vollständig deaktiviert.
DeallocationTypeMismatch false false Ermöglicht Fehlerberichte zu malloc/delete, new/free, new/delete[]
DeleteSizeMismatch true true Ermöglicht die Fehlerberichterstattung über Nichtübereinstimmungen zwischen den Größen von „Neu“ und „Löschen“.
ZeroContents false false Ermöglicht Null-Chunk-Inhalte bei Zuweisung und Freigabe.
allocator_may_return_null false false Gibt an, dass der Allokator null zurückgeben kann, wenn ein behebbarer Fehler auftritt, anstatt den Prozess zu beenden.
hard_rss_limit_mb 0 0 Wenn der RSS des Prozesses diesen Grenzwert erreicht, wird der Prozess beendet.
soft_rss_limit_mb 0 0 Wenn der RSS des Prozesses diesen Grenzwert erreicht, schlagen weitere Zuweisungen fehl oder geben null zurück (abhängig vom Wert von allocator_may_return_null ), bis der RSS wieder nach unten geht, um neue Zuweisungen zu ermöglichen.
allocator_release_to_os_interval_ms N / A 5000 Betrifft nur einen 64-Bit-Allokator. Wenn diese Option festgelegt ist, wird versucht, ungenutzten Speicher für das Betriebssystem freizugeben, jedoch nicht öfter als in diesem Intervall (in Millisekunden). Wenn der Wert negativ ist, wird dem Betriebssystem kein Speicher freigegeben.
abort_on_error true true Wenn festgelegt, ruft das Tool nach dem Drucken der Fehlermeldung abort() anstelle von _exit() auf.

Validierung

Derzeit gibt es keine CTS-Tests speziell für Scudo. Stellen Sie stattdessen sicher, dass CTS-Tests mit oder ohne aktiviertem Scudo für eine bestimmte Binärdatei bestanden werden, um sicherzustellen, dass es keine Auswirkungen auf das Gerät hat.

Fehlerbehebung

Wenn ein nicht behebbares Problem erkannt wird, zeigt der Allokator eine Fehlermeldung im Standardfehlerdeskriptor an und bricht dann den Prozess ab. Stacktraces, die zum Abbruch führen, werden im Systemprotokoll hinzugefügt. Die Ausgabe beginnt normalerweise mit Scudo ERROR: gefolgt von einer kurzen Zusammenfassung des Problems und etwaigen Hinweisen.

Hier finden Sie eine Liste der aktuellen Fehlermeldungen und ihrer möglichen Ursachen:

  • corrupted chunk header : Die Prüfsummenüberprüfung des Chunk-Headers ist fehlgeschlagen. Dies liegt wahrscheinlich an einem von zwei Dingen: Der Header wurde (teilweise oder vollständig) überschrieben oder der an die Funktion übergebene Zeiger ist kein Block.
  • race on chunk header : Zwei verschiedene Threads versuchen gleichzeitig, denselben Header zu manipulieren. Dies ist normalerweise symptomatisch für eine Race-Bedingung oder einen allgemeinen Mangel an Sperren beim Ausführen von Vorgängen für diesen Block.
  • invalid chunk state : Der Block befindet sich nicht im erwarteten Zustand für einen bestimmten Vorgang, z. B. ist er beim Versuch, ihn freizugeben, nicht zugewiesen oder beim Versuch, ihn wiederzuverwenden, nicht unter Quarantäne gestellt. Ein Double Free ist der typische Grund für diesen Fehler.
  • misaligned pointer : Grundlegende Ausrichtungsanforderungen werden streng durchgesetzt: 8 Byte auf 32-Bit-Plattformen und 16 Byte auf 64-Bit-Plattformen. Wenn ein an unsere Funktionen übergebener Zeiger nicht zu diesen passt, ist der an eine der Funktionen übergebene Zeiger nicht ausgerichtet.
  • allocation type mismatch : Wenn diese Option aktiviert ist, muss eine für einen Block aufgerufene Freigabefunktion mit dem Funktionstyp übereinstimmen, der für die Zuordnung aufgerufen wurde. Diese Art der Nichtübereinstimmung kann zu Sicherheitsproblemen führen.
  • invalid sized delete : Wenn der C++14-Löschoperator für die Größe verwendet wird und die optionale Prüfung aktiviert ist, besteht eine Diskrepanz zwischen der Größe, die beim Aufheben der Zuweisung eines Blocks übergeben wurde, und der Größe, die bei der Zuweisung angefordert wurde. Dabei handelt es sich in der Regel um ein Compilerproblem oder eine Typverwechslung des Objekts, dessen Zuordnung aufgehoben wird.
  • RSS limit exhausted : Das optional angegebene maximale RSS-Limit wurde überschritten.

Wenn Sie einen Absturz im Betriebssystem selbst debuggen, können Sie einen HWASan-Betriebssystem-Build verwenden. Wenn Sie einen Absturz in einer App debuggen, können Sie auch einen HWASan-App-Build verwenden.