ARM-Erweiterung für das Tagging des Arbeitsspeichers

Arm v9 führt Arm Memory ein Tagging Extension (MTE), eine Hardwareimplementierung von getaggte Speicher.

Grundsätzlich kennzeichnet MTE jede Arbeitsspeicherzuweisung/-zuweisung mit zusätzliche Metadaten. Sie weist einem Speicherstandort ein Tag zu, der dann die mit Zeigern verknüpft sind, die auf diesen Speicherort verweisen. Während der Laufzeit überprüft, ob der Zeiger und die Metadaten-Tags bei jedem Laden und Speicher übereinstimmen.

In Android 12 kann die Heap-Speicher-Zuweisung für Kernel und Userspace jede Zuweisung mit Metadaten. So lässt sich erkennen, Pufferüberlauf-Fehler, die die häufigste Ursache für unserer Codebasen.

MTE-Betriebsmodi

MTE hat drei Betriebsmodi:

  • Synchroner Modus (SYNC)
  • Asynchroner Modus (ASYNC)
  • Asymmetrischer Modus (ASYMM)

Synchroner Modus (SYNC)

Dieser Modus ist im Hinblick auf Fehlererkennung im Hinblick auf Leistung optimiert und kann als präzises Tool zur Fehlererkennung verwendet werden, wenn akzeptabel. Wenn MTE SYNC aktiviert ist, dient MTE SYNC als Abhilfe für die Sicherheit. Bei einem nicht übereinstimmenden Tag bricht der Prozessor die Ausführung sofort ab beendet den Prozess mit SIGSEGV (Code SEGV_MTESERR) sowie die vollständigen Informationen zum Arbeitsspeicherzugriff und zu den fehlerhafte Adresse.

Wir empfehlen, diesen Modus beim Testen als Alternative zu HWASan/KASAN oder in der Produktion, wenn der Zielprozess eine Schwachstelle darstellt Angriffsfläche. Wenn der ASYNC-Modus anzeigt, dass ein Fehler enthalten, können Sie einen genauen Fehlerbericht abrufen, indem Sie die Laufzeit-APIs verwenden, um den SYNC-Modus an.

Im SYNC-Modus zeichnet der Android-Allocator Stacktraces für alle Zuweisungen und Deallocations sowie verwendet sie, um bessere Fehlerberichte bereitzustellen, die eine Erläuterung eines Gedächtnisses enthalten. wie Use-After-Free oder buffer-Overflow, und die Stacktraces der relevante Gedächtnis-Ereignisse. Solche Berichte enthalten mehr Kontextinformationen und Fehler leichter nachzuverfolgen und zu beheben.

Asynchroner Modus (ASYNC)

Dieser Modus ist eher auf Leistung als auf Genauigkeit von Fehlerberichten ausgelegt und kann zur Erkennung von geringen Mehraufwand bei sicherheitsrelevanten Fehlern im Arbeitsspeicher verwendet werden.
Bei einem nicht übereinstimmenden Tag fährt der Prozessor bis zum nächsten Tag Kernel-Eintrag (z. B. Systemaufruf oder Timer-Unterbrechung), bei dem er beendet wird Prozess mit SIGSEGV (Code SEGV_MTEAERR) ohne die fehlerhafte Adresse oder den Arbeitsspeicherzugriff auf.
Wir empfehlen, diesen Modus in der Produktion auf gut getesteten Codebasen zu verwenden, Es ist bekannt, dass die Dichte der Sicherheitsfehler niedrig ist. Dies wird erreicht, indem den SYNC-Modus verwenden.

Asymmetrischer Modus (ASYMM)

Der asymmetrische MTE-Modus ist eine zusätzliche Funktion in Arm-Version 8.7-A und ermöglicht synchrone die Überprüfung von Lesevorgängen im Arbeitsspeicher und die asynchrone Prüfung von Speicherschreibvorgängen, mit einer ähnlichen Leistung wie der ASYNC-Modus. In den meisten Fällen ist eine Verbesserung gegenüber dem ASYNC-Modus. Wir empfehlen, ihn anstelle des ASYNC, wann immer es verfügbar ist.

Aus diesem Grund wird die asymmetrische API in keiner der unten beschriebenen APIs erwähnt. . Stattdessen kann das Betriebssystem so konfiguriert werden, dass immer der asymmetrische Modus verwendet wird, wenn Asynchron wird angefordert. Weitere Informationen dazu finden Sie im Abschnitt "CPU-spezifische bevorzugter MTE-Level .

MTE im Userspace

In den folgenden Abschnitten wird beschrieben, wie MTE für Systemprozesse aktiviert werden kann. und Apps. MTE ist standardmäßig deaktiviert, es sei denn, eine der folgenden Optionen ist für einen bestimmten Prozess festgelegt sind (für welche Komponenten MTE aktiviert ist).

MTE mit dem Build-System aktivieren

Als prozessweites Attribut wird MTE von der Build-Zeiteinstellung des der ausführbaren Hauptdatei. Mit den folgenden Optionen können Sie diese Einstellung für für einzelne ausführbare Dateien oder für ganze Unterverzeichnisse in der Quellstruktur. Die wird für Bibliotheken oder Ziele, die weder ausführbar noch testen.

1. Aktivierung von MTE in Android.bp (Beispiel) für ein bestimmtes Projekt:

MTE-Modus Einstellung
Asynchrone MTE
  sanitize: {
  memtag_heap: true,
  }
Synchroner MTE
  sanitize: {
  memtag_heap: true,
  diag: {
  memtag_heap: true,
  },
  }

oder in Android.mk:

MTE-Modus Einstellung
Asynchronous MTE LOCAL_SANITIZE := memtag_heap
Synchronous MTE LOCAL_SANITIZE := memtag_heap
LOCAL_SANITIZE_DIAG := memtag_heap

2. MTE mithilfe eines Produkts in einem Unterverzeichnis in der Quellstruktur aktivieren Variable:

MTE-Modus Einschlussliste Ausschlussliste
asynchron PRODUCT_MEMTAG_HEAP_ASYNC_INCLUDE_PATHS MEMTAG_HEAP_ASYNC_INCLUDE_PATHS PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS MEMTAG_HEAP_EXCLUDE_PATHS
Sync PRODUCT_MEMTAG_HEAP_SYNC_INCLUDE_PATHS MEMTAG_HEAP_SYNC_INCLUDE_PATHS

oder

MTE-Modus Einstellung
Asynchrone MTE MEMTAG_HEAP_ASYNC_INCLUDE_PATHS
Synchroner MTE MEMTAG_HEAP_SYNC_INCLUDE_PATHS

oder durch Angabe des Ausschlusspfads einer ausführbaren Datei:

MTE-Modus Einstellung
Asynchrone MTE PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS MEMTAG_HEAP_EXCLUDE_PATHS
Synchroner MTE

Beispiel (ähnliche Verwendung wie PRODUCT_CFI_INCLUDE_PATHS)

  PRODUCT_MEMTAG_HEAP_SYNC_INCLUDE_PATHS=vendor/$(vendor)
  PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS=vendor/$(vendor)/projectA \
                                    vendor/$(vendor)/projectB

MTE mithilfe von Systemeigenschaften aktivieren

Die obigen Build-Einstellungen können während der Laufzeit überschrieben werden. Legen Sie dazu den Parameter folgende Systemeigenschaft:

arm64.memtag.process.<basename> = (off|sync|async)

Dabei steht basename für den Basisnamen der ausführbaren Datei.

Um beispielsweise /system/bin/ping oder /data/local/tmp/ping festzulegen, Um den asynchronen MTE zu verwenden, verwenden Sie adb shell setprop arm64.memtag.process.ping async.

MTE mit einer Umgebungsvariable aktivieren

Eine weitere Möglichkeit, die Build-Einstellung zu überschreiben, ist das Definieren der Umgebung Variable: MEMTAG_OPTIONS=(off|sync|async) Wenn sowohl die Umgebungsvariable als auch die Systemeigenschaft definiert sind, Variable Vorrang hat.

MTE für Apps aktivieren

Wenn nicht angegeben, ist MTE standardmäßig deaktiviert, Apps, die MTE nutzen möchten, können dies tun, indem du android:memtagMode festlegst gemäß der <application> oder <process>-Tag im AndroidManifest.xml.

android:memtagMode=(off|default|sync|async)

Bei Festlegung im <application>-Tag wird der Parameter Attribut wirkt sich auf alle von der App verwendeten Prozesse aus und kann überschrieben werden. für einzelne Prozesse, indem Sie die <process>-Tag.

Zum Experimentieren: Kompatibilität mit Änderungen können Sie den Standardwert für memtagMode-Attribut für eine App, die im Manifest keinen Wert angeben (oder default.
Diese finden Sie im Menü für globale Einstellungen unter System > Advanced > Developer options > App Compatibility Changes. Einstellung NATIVE_MEMTAG_ASYNC oder NATIVE_MEMTAG_SYNC aktiviert MTE für eine bestimmte App.
Alternativ kann dies mit der am festgelegt werden. -Befehl so an:

$ adb shell am compat enable NATIVE_MEMTAG_[A]SYNC my.app.name

MTE-System-Image erstellen

Wir empfehlen dringend, MTE während der Entwicklung für alle nativen Binärprogramme zu aktivieren. und es bringt es auf. So lassen sich Sicherheitsrisiken frühzeitig erkennen und realistische Nutzerabdeckung, sofern in Test-Builds aktiviert.

Es wird dringend empfohlen, MTE während der Entwicklung im synchronen Modus für alle nativen Binärdateien zu aktivieren.

SANITIZE_TARGET=memtag_heap SANITIZE_TARGET_DIAG=memtag_heap m

Wie bei jeder Variablen im Build-System kann SANITIZE_TARGET auch als Umgebungsvariable oder make-Einstellung verwendet wird (z. B. in eine product.mk -Datei).
Beachten Sie, dass dadurch MTE für alle nativen Prozesse aktiviert wird, aber nicht für Apps (die aus zygote64 abgeleitet wurden), für die MTE verwendet werden kann gemäß der Anleitung oben aktiviert.

CPU-spezifische bevorzugte MTE-Ebene konfigurieren

Auf einigen CPUs kann die Leistung von MTE im ASYMM- oder sogar SYNC-Modi der folgenden ähneln: von ASYNC. Daher lohnt es sich, strengere Prüfungen dieser CPUs erforderlich sind, wenn ein weniger strenger Prüfmodus angefordert wird. um die Vorteile der strengeren Prüfungen zur Fehlererkennung zu nutzen, die Leistung beeinträchtigen.
Standardmäßig werden Prozesse, die für die Ausführung im ASYNC-Modus konfiguriert sind, in ASYNC ausgeführt Modus auf allen CPUs. Um den Kernel so zu konfigurieren, dass diese Prozesse im SYNC-Modus auf muss der Wert "sync" in den sysfs Eintrag /sys/devices/system/cpu/cpu<N>/mte_tcf_preferred beim Start . Dazu können Sie ein Initialisierungsskript verwenden. Um z. B. CPUs 0-1 zu konfigurieren, um Prozesse im ASYNC-Modus im SYNC-Modus auszuführen, und CPUs 2-3, um im ASYMM-Modus auszuführen. Folgendes kann der Init-Klausel eines Anbieter-Initialisierungsskripts hinzugefügt werden:

  write /sys/devices/system/cpu/cpu0/mte_tcf_preferred sync
  write /sys/devices/system/cpu/cpu1/mte_tcf_preferred sync
  write /sys/devices/system/cpu/cpu2/mte_tcf_preferred asymm
  write /sys/devices/system/cpu/cpu3/mte_tcf_preferred asymm

Tombstones aus Prozessen im ASYNC-Modus, die im SYNC-Modus ausgeführt werden, enthalten ein Den genauen Stacktrace der Position des Speicherfehlers. Sie werden jedoch nicht einen Zuordnungs- oder Deallocation-Stacktrace. Diese Stacktraces sind nur verfügbar, wenn der Prozess für die Ausführung im SYNC-Modus konfiguriert ist.

int mallopt(M_THREAD_DISABLE_MEM_INIT, level)

Dabei ist level 0 oder 1.
Deaktiviert die Initialisierung des Arbeitsspeichers in Malloc und vermeidet das Ändern von Speicher-Tags. es sei denn, dies ist zur Richtigkeit erforderlich.

int mallopt(M_MEMTAG_TUNING, level)

Dabei steht level für:

  • M_MEMTAG_TUNING_BUFFER_OVERFLOW
  • M_MEMTAG_TUNING_UAF

Hiermit wird eine Strategie für die Tag-Zuweisung ausgewählt.

  • Die Standardeinstellung ist M_MEMTAG_TUNING_BUFFER_OVERFLOW.
  • M_MEMTAG_TUNING_BUFFER_OVERFLOW: aktiviert den deterministischen Erkennung von linearen Pufferüberlauf- und Unterlauffehlern durch Zuweisung unterschiedlicher Tags auf benachbarte Zuweisungen anwenden. In diesem Modus ist die Wahrscheinlichkeit geringer, „Use After Free“-Programmfehler erkennen, da nur die Hälfte der möglichen Tag-Werte die für jeden Speicherort verfügbar sind. Beachten Sie, dass MTE die innerhalb derselben Tag-Granule (16-Byte-konformer Block) überlaufen und kleine Mengen auch in diesem Modus überläuft. Ein solcher Überlauf kann nicht der Grund für den Speicher sein da der Speicher innerhalb einer Granule nie für mehrere Zuweisungen.
  • M_MEMTAG_TUNING_UAF: aktiviert unabhängige, randomisierte Tags für eine einheitliche ~93% ige Wahrscheinlichkeit, dass sowohl räumliche (Pufferüberlauf) als auch temporale (Verwendung nach kostenloser) Bugs.

Neben den oben beschriebenen APIs möchten erfahrene Nutzer möglicherweise beachten Sie Folgendes:

  • Das Einrichten der PSTATE.TCO-Hardwareregisterkarte kann vorübergehend Tag-Überprüfung zu unterdrücken (Beispiel). Beispielsweise beim Kopieren eines Speicherbereichs mit unbekanntem Tag-Inhalt oder einen Leistungsengpass in einem Hot Loop zu beseitigen.
  • Bei Verwendung von M_HEAP_TAGGING_LEVEL_SYNC wird der Systemabsturz-Handler liefert zusätzliche Informationen wie Stacktraces für die Zuweisung und die Freigabe. Diese Funktion erfordert Zugriff auf die Tag-Bits und wird aktiviert, indem der SA_EXPOSE_TAGBITS , wenn Sie den Signal-Handler festlegen. Jedes Programm, das sein eigenes Signal festlegt und delegiert unbekannte Abstürze an das System. nicht identisch sind.

MTE im Kernel

Um MTE-beschleunigtes KASAN für den Kernel zu aktivieren, konfigurieren Sie den Kernel mit CONFIG_KASAN=y, CONFIG_KASAN_HW_TAGS=y. Diese Konfigurationen sind in GKI-Kernels standardmäßig aktiviert, beginnend mit Android 12-5.10.
Dies kann beim Booten mit den folgenden Befehlszeilenargumenten gesteuert werden:

  • kasan=[on|off]: KASAN aktivieren oder deaktivieren (Standard: on)
  • kasan.mode=[sync|async] – Zwischen synchronem und asynchronem Modus wählen (Standardeinstellung: sync)
  • kasan.stacktrace=[on|off] – ob erfasst werden soll Stacktraces (Standard: on)
    • ist es außerdem erforderlich, stack_depot_disable=off
  • kasan.fault=[report|panic]: Gibt an, ob nur der Bericht gedruckt werden soll, oder eine Panik im Kernel verursachen (Standardeinstellung: report). Unabhängig davon wird die Tag-Überprüfung nach dem ersten gemeldeten Fehler deaktiviert.

Wir empfehlen dringend, den SYNC-Modus während der Bereitstellung, Entwicklung und Tests durchführen. Diese Option sollte global für alle Prozesse aktiviert werden, die die Umgebungsvariable oder das Build-System verwenden. In diesem Modus werden Fehler erkannt zu Beginn des Entwicklungsprozesses, wird die Codebasis schneller stabilisiert und die Kosten für die spätere Erkennung von Fehlern in der Produktion entfallen.

Wir empfehlen dringend, den ASYNC-Modus in der Produktion zu verwenden. Dies sorgt für eine geringe um das Vorhandensein von Fehlern in Bezug auf die Speichersicherheit in einem Prozess zu erkennen, sowie weitere tief greifende Verteidigung. Sobald ein Fehler gefunden wurde, kann der Entwickler Nutzen Sie die Laufzeit-APIs, um in den SYNC-Modus zu wechseln und einen genauen Stacktrace zu erhalten aus einer Stichprobe von Nutzenden.

Wir empfehlen dringend, die CPU-spezifische bevorzugte MTE-Ebene für das SoC. Der Asymm-Modus hat in der Regel die gleichen Leistungsmerkmale wie ASYNC, und ist fast immer besser geeignet. Kleine Kerne nach Reihenfolge weisen oft ähnliche in allen drei Modi und kann so konfiguriert werden, dass SYNC bevorzugt wird.

Entwickler sollten das Vorhandensein von Abstürzen prüfen, indem sie Folgendes prüfen: /data/tombstones, logcat oder durch Überwachen des Anbieters DropboxManager für Programmfehler von Endnutzern. Weitere Informationen zum Debuggen von nativem Android-Code finden Sie unter finden Sie hier.

MTE-fähige Plattformkomponenten

In Android 12 verwenden eine Reihe von sicherheitskritischen Systemkomponenten MTE ASYNC um Abstürze von Endnutzern zu erkennen und als zusätzliche gestaffelte Sicherheitsebenen. Diese Komponenten sind:

  • Netzwerk-Daemons und Dienstprogramme (mit Ausnahme von netd)
  • Bluetooth, SecureElement, NFC-HALs und System-Apps
  • statsd Daemon
  • system_server
  • zygote64 (damit Apps die Verwendung von MTE aktivieren können)

Diese Ziele wurden anhand der folgenden Kriterien ausgewählt:

  • Ein privilegierter Prozess (definiert als ein Prozess, der Zugriff auf etwas hat) die die SELinux-Domain unprivileged_app nicht tut)
  • Verarbeitet nicht vertrauenswürdige Eingaben (Regel von zwei)
  • Akzeptable Leistungsabschwächung (Verlangsamung sorgt dafür, dass Nutzer nicht sichtbar sind) Latenz)

Wir empfehlen Anbietern, MTE in der Produktion für weitere Komponenten zu aktivieren, unter Berücksichtigung der oben genannten Kriterien. Wir empfehlen, während der Entwicklungsphase mithilfe des SYNC-Modus an, um Fehler leicht zu beheben und ASYNC beeinflusst ihre Leistung.
Für die Zukunft plant Android, die Liste der Systemkomponenten (MTE) zu erweitern, basierend auf den Leistungsmerkmalen zukünftiger Hardwaredesigns aktiviert.