UndefinedBehaviorSanitizer (UBSan) führt eine Instrumentierung zur Kompilierungszeit durch, um verschiedene Arten von undefiniertem Verhalten zu prüfen. UBSan kann zwar viele Fehler mit undefiniertem Verhalten erkennen, Android unterstützt jedoch Folgendes:
- Ausrichtung
- bool
- Grenzen
- enum
- float-cast-overflow
- float-divide-by-zero
- integer-divide-by-zero
- nonnull-Attribut
- null
- Hin- und Rückflug
- returns-nonnull-attribute
- shift-base
- shift-exponent
- signed-integer-overflow
- nicht erreichbar
- unsigned-integer-overflow
- vla-bound
„unsigned-integer-overflow“ ist zwar technisch gesehen kein undefiniertes Verhalten, wird aber in den Sanitizer aufgenommen und in vielen Android-Modulen verwendet, einschließlich der Mediaserver-Komponenten, um latente Sicherheitslücken durch Ganzzahlüberlauf zu beseitigen.
Implementierung
Im Android-Buildsystem können Sie UBSan global oder lokal aktivieren. Wenn Sie UBSan global aktivieren möchten, legen Sie SANITIZE_TARGET in Android.mk fest. Wenn Sie UBSan auf Modulebene aktivieren möchten, legen Sie LOCAL_SANITIZE fest und geben Sie in Android.mk die nicht definierten Verhaltensweisen an, nach denen gesucht werden soll. Beispiel:
LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_CFLAGS := -std=c11 -Wall -Werror -O0 LOCAL_SRC_FILES:= sanitizer-status.c LOCAL_MODULE:= sanitizer-status LOCAL_SANITIZE := alignment bounds null unreachable integer LOCAL_SANITIZE_DIAG := alignment bounds null unreachable integer include $(BUILD_EXECUTABLE)
Und die entsprechende Blueprint-Konfiguration (Android.bp):
cc_binary { cflags: [ "-std=c11", "-Wall", "-Werror", "-O0", ], srcs: ["sanitizer-status.c"], name: "sanitizer-status", sanitize: { misc_undefined: [ "alignment", "bounds", "null", "unreachable", "integer", ], diag: { misc_undefined: [ "alignment", "bounds", "null", "unreachable", "integer", ], }, }, }
UBSan-Tastenkombinationen
Android bietet außerdem zwei Tastenkürzel, integer
und default-ub
, um mehrere Desinfektionsmittel gleichzeitig zu aktivieren. Mit „integer“ werden integer-divide-by-zero
, signed-integer-overflow
und unsigned-integer-overflow
aktiviert.
default-ub
aktiviert die Prüfungen mit minimalen Compilerleistungsproblemen: bool, integer-divide-by-zero, return,
returns-nonnull-attribute, shift-exponent, unreachable and vla-bound
. Die Klasse „integer sanitizer“ kann mit SANITIZE_TARGET und LOCAL_SANITIZE verwendet werden, während „default-ub“ nur mit SANITIZE_TARGET verwendet werden kann.
Verbesserte Fehlerberichte
Die Standard-UBSan-Implementierung von Android ruft eine bestimmte Funktion auf, wenn ein undefiniertes Verhalten auftritt. Standardmäßig ist dies „abort“. Seit Oktober 2016 bietet UBSan auf Android jedoch eine optionale Laufzeitbibliothek, die detailliertere Fehlerberichte enthält, einschließlich Informationen zum Typ des aufgetretenen undefinierten Verhaltens sowie zu Datei- und Quellcodezeilen. Wenn Sie diese Fehlerberichte mit Ganzzahlprüfungen aktivieren möchten, fügen Sie einer Android.mk-Datei Folgendes hinzu:
LOCAL_SANITIZE:=integer LOCAL_SANITIZE_DIAG:=integer
Mit dem Wert „LOCAL_SANITIZE“ wird der Sanitizer während des Builds aktiviert. Mit LOCAL_SANITIZE_DIAG wird der Diagnosemodus für den angegebenen Sanitizer aktiviert. Es ist möglich, LOCAL_SANITIZE und LOCAL_SANITIZE_DIAG auf unterschiedliche Werte festzulegen. Es werden jedoch nur die Prüfungen in LOCAL_SANITIZE aktiviert. Wenn eine Prüfung nicht in LOCAL_SANITIZE, aber in LOCAL_SANITIZE_DIAG angegeben ist, ist die Prüfung nicht aktiviert und es werden keine Diagnosemeldungen ausgegeben.
Hier ein Beispiel für die Informationen, die von der UBSan-Laufzeitbibliothek bereitgestellt werden:
pixel-xl:/ # sanitizer-status ubsan sanitizer-status/sanitizer-status.c:53:6: runtime error: unsigned integer overflow: 18446744073709551615 + 1 cannot be represented in type 'size_t' (aka 'unsigned long')
Bereinigung von Ganzzahlüberläufen
Unbeabsichtigte Ganzzahlüberläufe können zu Speicherbeschädigungen oder Sicherheitslücken bei der Offenlegung von Informationen in Variablen führen, die mit Speicherzugriffen oder Speicherzuweisungen verknüpft sind. Um dies zu verhindern, haben wir in Android 7.0 die signierten und signaturlosen Ganzzahl-Overflow-Sanitizer von Clangs UndefinedBehaviorSanitizer (UBSan) hinzugefügt, um das Media Framework zu härten. In Android 9 haben wir UBSan auf mehr Komponenten ausgeweitet und die Build-Systemunterstützung für die Funktion verbessert.
Dadurch werden Prüfungen für arithmetische Vorgänge/Anweisungen hinzugefügt, die zu einem Überlauf führen können, um einen Prozess bei einem Überlauf sicher abzubrechen. Diese Sanitizer können eine ganze Klasse von Speicherbeschädigungen und Sicherheitslücken zur Offenlegung von Informationen beheben, bei denen ein Ganzzahlüberlauf die Ursache ist, z. B. die ursprüngliche Stagefright-Sicherheitslücke.
Beispiele und Quelle
Die Integer Overflow Sanitization (IntSan) wird vom Compiler bereitgestellt und fügt während der Kompilierung Instrumentierung in den Binärcode ein, um arithmetische Überläufe zu erkennen. Sie ist standardmäßig in verschiedenen Komponenten auf der gesamten Plattform aktiviert, z. B. in /platform/external/libnl/Android.bp
.
Implementierung
IntSan verwendet die Overflow-Sanitizer für signierte und signaturlose Ganzzahlen von UBSan. Diese Abhilfemaßnahme ist auf Modulebene aktiviert. Sie trägt dazu bei, wichtige Android-Komponenten zu schützen, und sollte nicht deaktiviert werden.
Wir empfehlen Ihnen dringend, die Bereinigung von Ganzzahlüberläufen für weitere Komponenten zu aktivieren. Ideale Kandidaten sind privilegierter nativer Code oder nativer Code, der nicht vertrauenswürdige Nutzereingaben analysiert. Der Sanitizer hat einen geringen Leistungsaufwand, der von der Verwendung des Codes und der Häufigkeit von arithmetischen Operationen abhängt. Rechnen Sie mit einem kleinen Overhead-Prozentsatz und testen Sie, ob die Leistung beeinträchtigt wird.
Unterstützung von IntSan in Makefiles
Wenn Sie IntSan in einem Makefile aktivieren möchten, fügen Sie Folgendes hinzu:
LOCAL_SANITIZE := integer_overflow # Optional features LOCAL_SANITIZE_DIAG := integer_overflow LOCAL_SANITIZE_BLOCKLIST := modulename_BLOCKLIST.txt
LOCAL_SANITIZE
nimmt eine durch Kommas getrennte Liste von Sanitizern entgegen.integer_overflow
ist eine vorkonfigurierte Gruppe von Optionen für die einzelnen Sanitizer für signed und unsigned integer overflow mit einer standardmäßigen BLOCKLIST.- Mit
LOCAL_SANITIZE_DIAG
wird der Diagnosemodus für die Desinfektionsgeräte aktiviert. Verwenden Sie den Diagnosemodus nur während des Tests, da bei Überläufen nicht abgebrochen wird, wodurch der Sicherheitsvorteil der Risikominderung vollständig aufgehoben wird. Weitere Informationen finden Sie unter Fehlerbehebung. - Mit
LOCAL_SANITIZE_BLOCKLIST
können Sie eine BLOCKLIST-Datei angeben, um zu verhindern, dass Funktionen und Quelldateien bereinigt werden. Weitere Informationen finden Sie unter Fehlerbehebung.
Wenn Sie die Kontrolle genauer festlegen möchten, können Sie die Sanitizer einzeln mit einem oder beiden Flags aktivieren:
LOCAL_SANITIZE := signed-integer-overflow, unsigned-integer-overflow LOCAL_SANITIZE_DIAG := signed-integer-overflow, unsigned-integer-overflow
Unterstützung von IntSan in Blueprint-Dateien
Wenn Sie die Bereinigung von Ganzzahlüberläufen in einer Blueprint-Datei wie /platform/external/libnl/Android.bp
aktivieren möchten, fügen Sie Folgendes hinzu:
sanitize: { integer_overflow: true, diag: { integer_overflow: true, }, BLOCKLIST: "modulename_BLOCKLIST.txt", },
Wie bei Make-Dateien ist die integer_overflow
-Eigenschaft eine vordefinierte Gruppe von Optionen für die einzelnen Signatur- und Unsigned-Integer-Overflow-Sanitizer mit einer standardmäßigen BLOCKLIST.
Mit den Properties diag
wird der Diagnosemodus für die Sanitizer aktiviert. Verwenden Sie den Diagnosemodus nur während des Tests. Im Diagnosemodus wird bei Überläufen nicht abgebrochen, wodurch der Sicherheitsvorteil der Risikominderung in Nutzerbuilds vollständig aufgehoben wird. Weitere Informationen finden Sie unter Fehlerbehebung.
Mit dem Attribut BLOCKLIST
kann eine BLOCKLIST-Datei angegeben werden, mit der Entwickler verhindern können, dass Funktionen und Quelldateien bereinigt werden. Weitere Informationen finden Sie unter Fehlerbehebung.
So aktivieren Sie die Sanitizer einzeln:
sanitize: { misc_undefined: ["signed-integer-overflow", "unsigned-integer-overflow"], diag: { misc_undefined: ["signed-integer-overflow", "unsigned-integer-overflow",], }, BLOCKLIST: "modulename_BLOCKLIST.txt", },
Fehlerbehebung
Wenn Sie die Bereinigung von Ganzzahlüberläufen in neuen Komponenten aktivieren oder auf Plattformbibliotheken zurückgreifen, die eine Bereinigung von Ganzzahlüberläufen haben, kann es zu einigen Problemen mit harmlosen Ganzzahlüberläufen kommen, die Abstürze verursachen. Sie sollten Komponenten mit aktivierter Bereinigung testen, damit harmlose Überläufe erkannt werden können.
Wenn Sie Abstürze suchen, die durch die Bereinigung in Nutzerbuilds verursacht wurden, suchen Sie nach SIGABRT
-Abstürzen mit Abbruchmeldungen, die auf einen von UBSan erkannten Überlauf hinweisen, z. B.:
pid: ###, tid: ###, name: Binder:### >>> /system/bin/surfaceflinger <<< signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- Abort message: 'ubsan: sub-overflow'
Der Stack-Trace sollte die Funktion enthalten, die den Abbruch verursacht. Overflows, die in Inline-Funktionen auftreten, sind jedoch möglicherweise nicht im Stack-Trace zu sehen.
Aktivieren Sie die Diagnose in der Bibliothek, die den Abbruch auslöst, um die Ursache leichter zu ermitteln, und versuchen Sie, den Fehler zu reproduzieren. Wenn die Diagnose aktiviert ist, wird der Prozess nicht abgebrochen, sondern fortgesetzt. Wenn die Ausführung nicht abgebrochen wird, lässt sich die Anzahl der harmlosen Overflows in einem bestimmten Ausführungspfad maximieren, ohne nach der Behebung jedes Bugs neu kompilieren zu müssen. Die Diagnose generiert eine Fehlermeldung mit der Zeilennummer und der Quelldatei, die den Abbruch verursacht haben:
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:2188:32: runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'size_t' (aka 'unsigned long')
Sobald Sie den problematischen arithmetischen Vorgang gefunden haben, prüfen Sie, ob der Überlauf harmlos und beabsichtigt ist (z.B. keine Sicherheitsrisiken birgt). So können Sie das Abbrechen des Sanitizers beheben:
- Code umschreiben, um einen Überlauf zu vermeiden (Beispiel)
- Explizit über die __builtin_*_overflow-Funktionen von Clang (Beispiel)
- Deaktivierung der Sanitierung in der Funktion durch Angabe des
no_sanitize
-Attributs (Beispiel) - Deaktivierung der Bereinigung einer Funktion oder Quelldatei über eine BLOCKLIST-Datei (Beispiel)
Sie sollten die möglichst detaillierte Lösung verwenden. Bei einer großen Funktion mit vielen arithmetischen Vorgängen und einem einzelnen Überlaufvorgang sollte beispielsweise der einzelne Vorgang neu strukturiert werden, anstatt die gesamte Funktion auf die BLOCKLISTE zu setzen.
Gängige Muster, die zu harmlosen Überläufen führen können, sind:
- Implizite Umwandlungen, bei denen ein Unsigned-Overflow auftritt, bevor eine Umwandlung in einen signierten Typ erfolgt (Beispiel)
- Löschen von Elementen aus einer Liste, bei dem der Schleifenindex beim Löschen dekrementiert wird (Beispiel)
- Zuweisung eines nicht signierten Typs zu -1 anstelle der Angabe des tatsächlichen Maximalwerts (Beispiel)
- Schleifen, die eine nicht signierte Ganzzahl in der Bedingung dekrementieren (Beispiel, Beispiel)
Entwicklern wird empfohlen, sich vor dem Deaktivieren der Bereinigung zu vergewissern, dass in Fällen, in denen der Bereiniger einen Überlauf erkennt, dieser tatsächlich harmlos ist und keine unbeabsichtigten Nebenwirkungen oder Sicherheitsrisiken birgt.
IntSan deaktivieren
Sie können IntSan mit BLOCKLISTs oder Funktionsattributen deaktivieren. Deaktivieren Sie sie sparsam und nur, wenn das Refactoring des Codes andernfalls nicht sinnvoll ist oder es zu Leistungseinbußen kommt.
Weitere Informationen zum Deaktivieren von IntSan mit Funktionsattributen und BLOCKLIST-Dateiformatierung finden Sie in der Upstream-Clang-Dokumentation. Die BLOCKLIST sollte auf den jeweiligen Sanitizer beschränkt werden. Verwenden Sie dazu Abschnittsnamen, die den Ziel-Sanitizer angeben, um Auswirkungen auf andere Sanitizer zu vermeiden.
Zertifizierungsstufe
Derzeit gibt es keinen CTS-Test speziell für die Bereinigung von Ganzzahlüberläufen. Achten Sie stattdessen darauf, dass die CTS-Tests mit oder ohne aktivierter IntSan-Funktion bestehen, um sicherzustellen, dass sie sich nicht auf das Gerät auswirkt.
Begrenzungssanierung
BoundsSanitizer (BoundSan) fügt Binärdateien Instrumentierung hinzu, um Grenzwertprüfungen für Arrayzugriffe einzufügen. Diese Prüfungen werden hinzugefügt, wenn der Compiler zur Kompilierungszeit nicht nachweisen kann, dass der Zugriff sicher ist, und wenn die Größe des Arrays zur Laufzeit bekannt ist, damit eine Prüfung möglich ist. In Android 10 wird BoundSan in Bluetooth und Codecs bereitgestellt. BoundSan wird vom Compiler bereitgestellt und ist standardmäßig in verschiedenen Komponenten auf der gesamten Plattform aktiviert.
Implementierung
BoundSan verwendet den Grenzwert-Sanitizer von UBSan. Diese Abhilfemaßnahme ist auf Modulebene aktiviert. Sie trägt dazu bei, wichtige Android-Komponenten zu schützen, und sollte nicht deaktiviert werden.
Wir empfehlen Ihnen dringend, BoundSan für weitere Komponenten zu aktivieren. Ideale Kandidaten sind privilegierter nativer Code oder komplexer nativer Code, der nicht vertrauenswürdige Nutzereingaben analysiert. Der Leistungsoverhead, der mit der Aktivierung von BoundSan verbunden ist, hängt von der Anzahl der Arrayzugriffe ab, die nicht als sicher nachgewiesen werden können. Im Durchschnitt ist mit einem geringen Overhead-Prozentsatz zu rechnen. Prüfen Sie, ob die Leistung beeinträchtigt wird.
BoundSan in Blueprint-Dateien aktivieren
BoundSan kann in Blueprint-Dateien aktiviert werden, indem dem Attribut „Sanitize“ misc_undefined
für Binär- und Bibliotheksmodule der Wert "bounds"
hinzugefügt wird:
sanitize: { misc_undefined: ["bounds"], diag: { misc_undefined: ["bounds"], }, BLOCKLIST: "modulename_BLOCKLIST.txt",
diag
Mit der Property diag
wird der Diagnosemodus für die Sanitizer aktiviert.
Verwenden Sie den Diagnosemodus nur während des Tests. Im Diagnosemodus wird bei Überläufen nicht abgebrochen, was den Sicherheitsvorteil der Risikominderung aufhebt und einen höheren Leistungsoverhead mit sich bringt. Daher wird er für Produktionsbuilds nicht empfohlen.
BLOCKLISTE
Mit der BLOCKLIST
-Eigenschaft kann eine BLOCKLIST-Datei angegeben werden, mit der Entwickler verhindern können, dass Funktionen und Quelldateien bereinigt werden. Verwenden Sie diese Eigenschaft nur, wenn die Leistung ein Problem darstellt und die ausgewählten Dateien/Funktionen einen wesentlichen Beitrag dazu leisten. Prüfen Sie diese Dateien/Funktionen manuell, um sicherzustellen, dass Arrayzugriffe sicher sind. Weitere Informationen finden Sie unter Fehlerbehebung.
BoundSan in Makefiles aktivieren
BoundSan kann in Makefiles aktiviert werden, indem der Variablen LOCAL_SANITIZE
für Binär- und Bibliotheksmodule "bounds"
hinzugefügt wird:
LOCAL_SANITIZE := bounds # Optional features LOCAL_SANITIZE_DIAG := bounds LOCAL_SANITIZE_BLOCKLIST := modulename_BLOCKLIST.txt
Für LOCAL_SANITIZE
kann eine durch Kommas getrennte Liste von Sanierern verwendet werden.
LOCAL_SANITIZE_DIAG
aktiviert den Diagnosemodus. Verwenden Sie den Diagnosemodus nur während des Tests. Im Diagnosemodus wird bei Überläufen nicht abgebrochen, was den Sicherheitsvorteil der Risikominderung aufhebt und einen höheren Leistungsoverhead mit sich bringt. Daher wird er für Produktionsbuilds nicht empfohlen.
Mit LOCAL_SANITIZE_BLOCKLIST
kann eine BLOCKLIST-Datei angegeben werden, mit der Entwickler verhindern können, dass Funktionen und Quelldateien bereinigt werden. Verwenden Sie diese Eigenschaft nur, wenn die Leistung ein Problem darstellt und die ausgewählten Dateien/Funktionen einen wesentlichen Beitrag dazu leisten. Prüfen Sie diese Dateien/Funktionen manuell, um sicherzustellen, dass Arrayzugriffe sicher sind. Weitere Informationen finden Sie unter Fehlerbehebung.
BoundSan deaktivieren
Sie können BoundSan in Funktionen und Quelldateien mit BLOCKLISTS oder Funktionsattributen deaktivieren. Es empfiehlt sich, BoundSan aktiviert zu lassen. Deaktivieren Sie es nur, wenn die Funktion oder Datei einen großen Leistungsoverhead verursacht und die Quelle manuell geprüft wurde.
Weitere Informationen zum Deaktivieren von BoundSan mit Funktionsattributen und BLOCKLIST-Dateiformatierung finden Sie in der Clang LLVM-Dokumentation. Beschränken Sie die BLOCKLISTE auf den jeweiligen Sanitizer, indem Sie Abschnittsnamen verwenden, in denen der Ziel-Sanitizer angegeben ist, um Auswirkungen auf andere Sanitizer zu vermeiden.
Zertifizierungsstufe
Es gibt keinen CTS-Test speziell für BoundSan. Achten Sie stattdessen darauf, dass die CTS-Tests mit oder ohne aktiviertem BoundSan bestehen, um sicherzustellen, dass es keine Auswirkungen auf das Gerät hat.
Fehlerbehebung
Testen Sie die Komponenten gründlich, nachdem Sie BoundSan aktiviert haben, um sicherzustellen, dass alle zuvor nicht erkannten Zugriffe außerhalb des Gültigkeitsbereichs behoben wurden.
BoundSan-Fehler sind leicht zu erkennen, da sie die folgende Meldung zum Abbruch des Tombstones enthalten:
pid: ###, tid: ###, name: Binder:### >>> /system/bin/foobar <<< signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- Abort message: 'ubsan: out-of-bounds'
Wenn der Dienst im Diagnosemodus ausgeführt wird, werden die Quelldatei, die Zeilennummer und der Indexwert in logcat
ausgegeben. Standardmäßig wird in diesem Modus keine Abbruchsnachricht ausgegeben. Prüfen Sie logcat
auf Fehler.
external/foo/bar.c:293:13: runtime error: index -1 out of bounds for type 'int [24]'