Undefiniertes VerhaltenSanitizer

UndefinedBehaviorSanitizer (UBSan) führt eine Instrumentierung zur Kompilierungszeit durch, um auf verschiedene Arten von undefiniertem Verhalten zu prüfen. Während UBSan in der Lage ist , viele undefinierte Verhaltensfehler zu erkennen, unterstützt Android:

  • Ausrichtung
  • bool
  • Grenzen
  • Aufzählung
  • Float-Cast-Überlauf
  • float-division-by-null
  • Ganzzahl durch Null dividieren
  • Nicht-Null-Attribut
  • Null
  • zurückkehren
  • gibt ein Nicht-Null-Attribut zurück
  • Schichtbasis
  • Verschiebungsexponent
  • vorzeichenbehafteter Ganzzahlüberlauf
  • unerreichbar
  • vorzeichenloser Ganzzahlüberlauf
  • vla-gebunden

Unsigned-Integer-Overflow ist zwar kein technisch undefiniertes Verhalten, ist aber im Sanitizer enthalten und wird in vielen Android-Modulen, einschließlich der Mediaserver-Komponenten, verwendet, um etwaige latente Schwachstellen durch Integer-Überlauf zu beseitigen.

Implementierung

Im Android-Build-System können Sie UBSan global oder lokal aktivieren. Um UBSan global zu aktivieren, legen Sie SANITIZE_TARGET in Android.mk fest. Um UBSan auf Modulebene zu aktivieren, legen Sie LOCAL_SANITIZE fest und geben Sie die undefinierten Verhaltensweisen an, nach denen Sie in Android.mk suchen möchten. Zum 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-Verknüpfungen

Android verfügt außerdem über zwei Verknüpfungen, integer und default-ub , um eine Reihe von Desinfektionsmitteln gleichzeitig zu aktivieren. integer ermöglicht integer-divide-by-zero , signed-integer-overflow und unsigned-integer-overflow . default-ub aktiviert die Prüfungen, die minimale Probleme mit der Compilerleistung haben: bool, integer-divide-by-zero, return, returns-nonnull-attribute, shift-exponent, unreachable and vla-bound . Die Integer-Sanitizer-Klasse kann mit SANITIZE_TARGET und LOCAL_SANITIZE verwendet werden, während default-ub nur mit SANITIZE_TARGET verwendet werden kann.

Bessere Fehlerberichterstattung

Die standardmäßige UBSan-Implementierung von Android ruft eine bestimmte Funktion auf, wenn undefiniertes Verhalten auftritt. Standardmäßig ist diese Funktion abgebrochen. Seit Oktober 2016 verfügt UBSan für Android jedoch über eine optionale Laufzeitbibliothek, die detailliertere Fehlerberichte bietet, einschließlich der Art des aufgetretenen undefinierten Verhaltens sowie Informationen zu Datei- und Quellcodezeilen. Um diese Fehlerberichterstattung mit Ganzzahlprüfungen zu aktivieren, fügen Sie einer Android.mk-Datei Folgendes hinzu:

LOCAL_SANITIZE:=integer
LOCAL_SANITIZE_DIAG:=integer

Der LOCAL_SANITIZE-Wert aktiviert den Sanitizer während des Builds. LOCAL_SANITIZE_DIAG aktiviert den Diagnosemodus für das angegebene Desinfektionsmittel. Es ist möglich, LOCAL_SANITIZE und LOCAL_SANITIZE_DIAG auf unterschiedliche Werte zu setzen, aber nur die Prüfungen in LOCAL_SANITIZE sind aktiviert. Wenn in LOCAL_SANITIZE keine Prüfung, aber in LOCAL_SANITIZE_DIAG angegeben ist, ist die Prüfung nicht aktiviert und es werden keine Diagnosemeldungen ausgegeben.

Hier ist 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 verbunden sind. Um dem entgegenzuwirken, haben wir die signierten und nicht signierten Integer-Overflow-Desinfektionsmittel UnfineBehaviorSanitizer (UBSan) von Clang hinzugefügt, um das Medien-Framework in Android 7.0 zu härten . In Android 9 haben wir UBSan erweitert, um mehr Komponenten abzudecken und die Build-System-Unterstützung dafür zu verbessern.

Dies dient dazu, Prüfungen für arithmetische Operationen/Anweisungen hinzuzufügen, die möglicherweise überlaufen, um einen Prozess sicher abzubrechen, wenn es zu einem Überlauf kommt. Diese Sanitizer können eine ganze Klasse von Schwachstellen hinsichtlich Speicherbeschädigung und Offenlegung von Informationen abmildern, bei denen die Ursache ein Integer-Überlauf ist, wie beispielsweise die ursprüngliche Stagefright-Schwachstelle.

Beispiele und Quelle

Integer Overflow Sanitization (IntSan) wird vom Compiler bereitgestellt und fügt während der Kompilierungszeit Instrumentierung in die Binärdatei ein, um arithmetische Überläufe zu erkennen. Es ist standardmäßig in verschiedenen Komponenten der Plattform aktiviert, zum Beispiel /platform/external/libnl/Android.bp .

Implementierung

IntSan verwendet die vorzeichenbehafteten und vorzeichenlosen Integer-Überlauf-Desinfektionsmittel von UBSan. Diese Schadensbegrenzung wird auf Modulebene aktiviert. Es trägt dazu bei, kritische Komponenten von Android zu schützen und sollte nicht deaktiviert werden.

Wir empfehlen Ihnen dringend, die Integer Overflow Sanitization für zusätzliche Komponenten zu aktivieren. Ideale Kandidaten sind privilegierter nativer Code oder nativer Code, der nicht vertrauenswürdige Benutzereingaben analysiert. Mit dem Sanitizer ist ein geringer Leistungsaufwand verbunden, der von der Codenutzung und der Verbreitung arithmetischer Operationen abhängt. Erwarten Sie einen geringen Overhead-Prozentsatz und testen Sie, ob die Leistung ein Problem darstellt.

Unterstützung von IntSan in Makefiles

Um IntSan in einem Makefile zu aktivieren, fügen Sie Folgendes hinzu:

LOCAL_SANITIZE := integer_overflow
    # Optional features
    LOCAL_SANITIZE_DIAG := integer_overflow
    LOCAL_SANITIZE_BLOCKLIST := modulename_BLOCKLIST.txt
  • LOCAL_SANITIZE verwendet eine durch Kommas getrennte Liste von Sanitizern, wobei integer_overflow ein vorgefertigter Satz von Optionen für die einzelnen vorzeichenbehafteten und vorzeichenlosen Integer-Overflow-Desinfektionsmittel mit einer Standardliste BLOCKLIST ist.
  • LOCAL_SANITIZE_DIAG aktiviert den Diagnosemodus für die Desinfektionsmittel. Verwenden Sie den Diagnosemodus nur während des Tests, da dieser bei Überläufen nicht abbricht, wodurch der Sicherheitsvorteil der Schadensbegrenzung vollständig zunichte gemacht wird. Weitere Einzelheiten finden Sie unter Fehlerbehebung .
  • LOCAL_SANITIZE_BLOCKLIST können Sie eine BLOCKLIST-Datei angeben, um zu verhindern, dass Funktionen und Quelldateien bereinigt werden. Weitere Einzelheiten finden Sie unter Fehlerbehebung .

Wenn Sie eine detailliertere Kontrolle wünschen, aktivieren Sie die Desinfektionsmittel einzeln mit einem oder beiden Flags:

LOCAL_SANITIZE := signed-integer-overflow, unsigned-integer-overflow
    LOCAL_SANITIZE_DIAG := signed-integer-overflow, unsigned-integer-overflow

Unterstützung von IntSan in Blueprint-Dateien

Um die Bereinigung von Ganzzahlüberläufen in einer Blueprint-Datei wie /platform/external/libnl/Android.bp zu aktivieren, fügen Sie Folgendes hinzu:

   sanitize: {
          integer_overflow: true,
          diag: {
              integer_overflow: true,
          },
          BLOCKLIST: "modulename_BLOCKLIST.txt",
       },

Wie bei Make-Dateien handelt es sich bei der Eigenschaft integer_overflow um einen vorgefertigten Satz von Optionen für die einzelnen vorzeichenbehafteten und vorzeichenlosen Integer-Overflow-Desinfektionsmittel mit einer standardmäßigen BLOCKLIST .

Der diag Eigenschaftssatz aktiviert den Diagnosemodus für die Desinfektionsmittel. Verwenden Sie den Diagnosemodus nur während des Tests. Der Diagnosemodus wird bei Überläufen nicht abgebrochen, wodurch der Sicherheitsvorteil der Schadensbegrenzung in Benutzerbuilds vollständig zunichte gemacht wird. Weitere Einzelheiten finden Sie unter Fehlerbehebung .

Die BLOCKLIST Eigenschaft ermöglicht die Angabe einer BLOCKLIST-Datei, mit der Entwickler verhindern können, dass Funktionen und Quelldateien bereinigt werden. Weitere Einzelheiten finden Sie unter Fehlerbehebung .

Um die Desinfektionsmittel einzeln zu aktivieren, verwenden Sie:

   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 sich auf Plattformbibliotheken verlassen, die über eine Bereinigung von Ganzzahlüberläufen verfügen, können einige Probleme mit harmlosen Ganzzahlüberläufen auftreten, die zu Abbrüchen führen. Sie sollten Komponenten mit aktivierter Desinfektion testen, um sicherzustellen, dass harmlose Überläufe entdeckt werden können.

Um Abbrüche zu finden, die durch Bereinigung in Benutzer-Builds verursacht wurden, suchen Sie nach SIGABRT Abstürzen mit Abbruchmeldungen, die auf einen von UBSan abgefangenen Überlauf hinweisen, wie zum Beispiel:

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 hat. Überläufe, die in Inline-Funktionen auftreten, sind jedoch möglicherweise nicht im Stack-Trace erkennbar.

Um die Grundursache einfacher zu ermitteln, aktivieren Sie die Diagnose in der Bibliothek, die den Abbruch auslöst, und versuchen Sie, den Fehler zu reproduzieren. Bei aktivierter Diagnose wird der Prozess nicht abgebrochen , sondern weiter ausgeführt. Wenn Sie nicht abbrechen, können Sie die Anzahl harmloser Überläufe in einem bestimmten Ausführungspfad maximieren, ohne nach der Behebung jedes Fehlers eine Neukompilierung durchführen zu müssen. Die Diagnose erzeugt eine Fehlermeldung, die die Zeilennummer und die Quelldatei enthält, die den Abbruch verursacht hat:

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 die problematische arithmetische Operation gefunden wurde, stellen Sie sicher, dass der Überlauf harmlos und beabsichtigt ist (z. B. keine Auswirkungen auf die Sicherheit hat). Sie können den Desinfektionsabbruch folgendermaßen beheben:

  • Den Code umgestalten, um den Überlauf zu vermeiden ( Beispiel )
  • Expliziter Überlauf über Clangs __builtin_*_overflow- Funktionen ( Beispiel )
  • Deaktivieren der Bereinigung in der Funktion durch Angabe des Attributs no_sanitize ( Beispiel )
  • Deaktivieren der Bereinigung einer Funktion oder Quelldatei über eine BLOCKLIST-Datei ( Beispiel )

Sie sollten eine möglichst granulare Lösung verwenden. Beispielsweise sollte bei einer großen Funktion mit vielen arithmetischen Operationen und einer einzelnen überlaufenden Operation die einzelne Operation umgestaltet werden und nicht die gesamte Funktion mit BLOCKLIST versehen werden.

Zu den häufigen Mustern, die zu harmlosen Überläufen führen können, gehören:

  • Implizite Umwandlungen , bei denen ein vorzeichenloser Überlauf auftritt, bevor in einen vorzeichenbehafteten Typ umgewandelt wird ( Beispiel )
  • Löschungen verknüpfter Listen, die den Schleifenindex beim Löschen dekrementieren ( Beispiel )
  • Zuweisen eines vorzeichenlosen Typs zu -1, anstatt den tatsächlichen Maximalwert anzugeben ( Beispiel )
  • Schleifen, die eine vorzeichenlose Ganzzahl in der Bedingung dekrementieren ( Beispiel , Beispiel )

Es wird empfohlen, dass Entwickler in Fällen, in denen das Desinfektionsmittel einen Überlauf erkennt, sicherstellen, dass dieser tatsächlich harmlos ist und keine unbeabsichtigten Nebenwirkungen oder Auswirkungen auf die Sicherheit aufweist, bevor sie die Desinfektion deaktivieren.

Deaktivieren von IntSan

Sie können IntSan mit BLOCKLISTs oder Funktionsattributen deaktivieren. Deaktivieren Sie die Funktion nur sparsam und nur dann, wenn die Umgestaltung des Codes aus anderen Gründen unzumutbar ist oder wenn es zu einem problematischen Leistungsaufwand kommt.

Weitere Informationen zum Deaktivieren von IntSan mit Funktionsattributen und BLOCKLIST-Dateiformatierung finden Sie in der Upstream-Clang-Dokumentation. BLOCKLISTing sollte auf das jeweilige Desinfektionsmittel beschränkt werden, indem Abschnittsnamen verwendet werden, die das Zieldesinfektionsmittel angeben, um Auswirkungen auf andere Desinfektionsmittel zu vermeiden.

Validierung

Derzeit gibt es keinen CTS-Test speziell für die Sanitisierung von Ganzzahlüberläufen. Stellen Sie stattdessen sicher, dass CTS-Tests mit oder ohne aktiviertem IntSan bestanden werden, um sicherzustellen, dass es keine Auswirkungen auf das Gerät hat.

Grenzendesinfektion

BoundsSanitizer (BoundSan) fügt Binärdateien Instrumentierung hinzu, um Grenzprüfungen um Array-Zugriffe herum 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, sodass sie überprüft werden kann. Android 10 stellt BoundSan in Bluetooth und Codecs bereit. BoundSan wird vom Compiler bereitgestellt und ist standardmäßig in verschiedenen Komponenten der Plattform aktiviert.

Implementierung

BoundSan verwendet den Grenzendesinfektionsmittel von UBSan . Diese Schadensbegrenzung wird auf Modulebene aktiviert. Es trägt dazu bei, wichtige Android-Komponenten zu schützen und sollte nicht deaktiviert werden.

Wir empfehlen Ihnen dringend, BoundSan für zusätzliche Komponenten zu aktivieren. Ideale Kandidaten sind privilegierter nativer Code oder komplexer nativer Code, der nicht vertrauenswürdige Benutzereingaben analysiert. Der mit der Aktivierung von BoundSan verbundene Leistungsaufwand hängt von der Anzahl der Array-Zugriffe ab, die nicht als sicher erwiesen werden können. Erwarten Sie im Durchschnitt einen geringen Overhead-Prozentsatz und testen Sie, ob die Leistung ein Problem darstellt.

BoundSan in Blueprint-Dateien aktivieren

BoundSan kann in Blueprint-Dateien aktiviert werden, indem "bounds" zur misc_undefined sanitize-Eigenschaft für Binär- und Bibliotheksmodule hinzugefügt wird:

    sanitize: {
       misc_undefined: ["bounds"],
       diag: {
          misc_undefined: ["bounds"],
       },
       BLOCKLIST: "modulename_BLOCKLIST.txt",
diag

Die diag Eigenschaft aktiviert den Diagnosemodus für die Desinfektionsmittel. Verwenden Sie den Diagnosemodus nur während des Tests. Der Diagnosemodus wird bei Überläufen nicht abgebrochen, was den Sicherheitsvorteil der Schadensbegrenzung zunichte macht und einen höheren Leistungsaufwand mit sich bringt. Daher wird er nicht für Produktions-Builds empfohlen.

BLOCKLISTE

Die BLOCKLIST Eigenschaft ermöglicht die Angabe einer BLOCKLIST-Datei, die Entwickler verwenden können, um zu verhindern, dass Funktionen und Quelldateien bereinigt werden. Verwenden Sie diese Eigenschaft nur, wenn die Leistung ein Problem darstellt und die Zieldateien/-funktionen einen wesentlichen Beitrag leisten. Überprüfen Sie diese Dateien/Funktionen manuell, um sicherzustellen, dass Array-Zugriffe sicher sind. Weitere Einzelheiten finden Sie unter Fehlerbehebung .

BoundSan in Makefiles aktivieren

BoundSan kann in Makefiles aktiviert werden, indem "bounds" zur Variablen LOCAL_SANITIZE für Binär- und Bibliotheksmodule hinzugefügt werden:

    LOCAL_SANITIZE := bounds
    # Optional features
    LOCAL_SANITIZE_DIAG := bounds
    LOCAL_SANITIZE_BLOCKLIST := modulename_BLOCKLIST.txt

LOCAL_SANITIZE akzeptiert eine durch Komma getrennte Liste von Desinfektionsmitteln.

LOCAL_SANITIZE_DIAG aktiviert den Diagnosemodus. Verwenden Sie den Diagnosemodus nur während des Tests. Der Diagnosemodus wird bei Überläufen nicht abgebrochen, was den Sicherheitsvorteil der Schadensbegrenzung zunichte macht und einen höheren Leistungsaufwand mit sich bringt. Daher wird er nicht für Produktions-Builds empfohlen.

LOCAL_SANITIZE_BLOCKLIST ermöglicht die Angabe einer BLOCKLIST-Datei, 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 Zieldateien/-funktionen einen wesentlichen Beitrag leisten. Überprüfen Sie diese Dateien/Funktionen manuell, um sicherzustellen, dass Array-Zugriffe sicher sind. Weitere Einzelheiten finden Sie unter Fehlerbehebung .

BoundSan wird deaktiviert

Sie können BoundSan in Funktionen und Quelldateien mit BLOCKLISTs oder Funktionsattributen deaktivieren. Es ist am besten, BoundSan aktiviert zu lassen. Deaktivieren Sie es daher nur, wenn die Funktion oder Datei einen großen Leistungsaufwand verursacht und die Quelle manuell überprüft wurde.

Weitere Informationen zum Deaktivieren von BoundSan mit Funktionsattributen und BLOCKLIST-Dateiformatierung finden Sie in der Clang LLVM- Dokumentation . Beschränken Sie die BLOCKLISTing auf das jeweilige Desinfektionsmittel, indem Sie Abschnittsnamen verwenden, die das Zieldesinfektionsmittel angeben, um Auswirkungen auf andere Desinfektionsmittel zu vermeiden.

Validierung

Es gibt keinen CTS-Test speziell für BoundSan. Stellen Sie stattdessen sicher, dass CTS-Tests mit oder ohne aktiviertem BoundSan bestanden werden, 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 unentdeckten Zugriffe außerhalb der Grenzen berücksichtigt werden.

BoundSan-Fehler können leicht identifiziert werden, da sie die folgende Tombstone-Abbruchmeldung enthalten:

    pid: ###, tid: ###, name: Binder:###  >>> /system/bin/foobar <<<
    signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
    Abort message: 'ubsan: out-of-bounds'

Bei der Ausführung im Diagnosemodus werden die Quelldatei, die Zeilennummer und der Indexwert in logcat ausgegeben. Standardmäßig gibt dieser Modus keine Abbruchmeldung aus. Überprüfen Sie logcat , um nach Fehlern zu suchen.

    external/foo/bar.c:293:13: runtime error: index -1 out of bounds for type 'int [24]'