Implementierung von dm-verity

Android 4.4 und höher unterstützt den verifizierten Bootmodus durch die optionale dm-verity-Kernelfunktion (device-mapper-verity), die transparente Integritätsprüfung blockierter Geräte. dm-verity hilft, persistente Rootkits zu verhindern die Root-Berechtigungen haben und Geräte kompromittieren kann. Dieses können Android-Nutzer beim Starten eines Geräts sicher sein, wie sie zuletzt verwendet wurde.

Potenziell schädliche Apps (PSAs) mit Root-Berechtigungen können vor Programme zur Erkennung von Systemausfällen und maskieren sich anderweitig. Die Rooting-Software kann da sie oft privilegierter sind als die Detektoren. Software zum „Lügen“ Erkennungsprogrammen hinzugefügt.

Mit der dm-verity-Funktion können Sie ein Blockgerät, den zugrunde liegenden Speicher, Schicht des Dateisystems und ermitteln, ob sie dem erwarteten Konfiguration. Dazu wird ein kryptografischer Hash-Baum verwendet. Für jeden Block (normalerweise 4k) ist ein SHA256-Hash.

Da die Hashwerte in einer Baumstruktur von Seiten gespeichert werden, kann nur die oberste Ebene „Stamm“ Hash muss vertrauenswürdig sein, damit der Rest der Struktur verifiziert werden kann. Die Fähigkeit, einen der Blöcke zu ändern, würde das Zerbrechen des kryptografischen Hashs gleich. Das folgende Diagramm zeigt diese Struktur.

dm-verity-hash-table

Abbildung 1: dm-verity-Hash-Tabelle

Die Bootpartition enthält einen öffentlichen Schlüssel, der verifiziert werden muss. extern vom Gerätehersteller erhalten. Mit diesem Schlüssel wird die Signatur verifiziert. für diesen Hash und prüfen Sie, ob die Systempartition des Geräts geschützt ist. unverändert lassen.

Betrieb

Der dm-verity-Schutz befindet sich im Kernel. Wenn das Rooting der Software die bevor der Kernel erstellt wird, behält er diesen Zugriff bei. Um dies zu vermeiden Risiko eingehen, überprüfen die meisten Hersteller den Kernel mit einem in das Gerät gebrannten Schlüssel. Dieser Schlüssel kann in fabrikneuem Zustand nicht mehr geändert werden.

Hersteller verwenden diesen Schlüssel, um die Signatur auf der ersten Ebene zu verifizieren. Bootloader, der wiederum die Signatur auf nachfolgenden Ebenen überprüft, den Anwendungs-Bootloader und schließlich den Kernel. Jeder Hersteller, der profitieren Sie von bestätigten boot sollte eine Methode zum Prüfen der Kernel-Integrität vorhanden sein. Wenn der Kernel verifiziert wurde, kann er ein Blockgerät betrachten und überprüfen Sie die Verbindung während der Bereitstellung.

Eine Möglichkeit, ein Blockgerät zu verifizieren, besteht darin, seinen Inhalt direkt zu hashen in einen gespeicherten Wert. Die Bestätigung eines komplett blockierten Geräts kann jedoch länger dauern und einen großen Teil des Stromverbrauchs eines Geräts verbrauchen. Geräte benötigen und vor der Nutzung erheblich entladen.

Stattdessen überprüft dm-verity Blockierungen einzeln und nur dann, wenn jeder Block Zugriff haben. Beim Einlesen in den Arbeitsspeicher wird der Block parallel gehasht. Der Hashwert und den Baum überprüft. Und da das Lesen des Blocks so teuer ist, ist die durch diese Block-Level-Überprüfung verursachte Latenz vergleichsweise nominal.

Wenn die Überprüfung fehlschlägt, gibt das Gerät einen E/A-Fehler aus, der auf die Blockierung hinweist. kann nicht gelesen werden. Es scheint, als sei das Dateisystem beschädigt, zu erwarten war.

Anwendungen können ohne die resultierenden Daten fortfahren, zum Beispiel Diese Ergebnisse sind nicht für die primäre Funktion der Anwendung erforderlich. Sie können jedoch Wenn die Anwendung ohne die Daten nicht fortgesetzt werden kann, schlägt sie fehl.

Fehlerkorrektur weiterleiten

Android 7.0 und höher verbessern die dm-verity-Robustheit mit Weiterleitungsfehlern Korrektur (FEC). Die AOSP-Implementierung beginnt mit der allgemeinen Reed-Solomon-Fehlerkorrekturcode und wendet einen Technik namens Verschränkung, um den Raum-Overhead zu reduzieren und die Anzahl der beschädigten Blöcke, die wiederhergestellt werden können. Weitere Informationen zu FEC finden Sie unter Streng erzwungener verifizierter Bootmodus mit Fehlerkorrektur.

Implementierung

Zusammenfassung

  1. Generieren Sie ein ext4-System-Image.
  2. Generieren Sie einen Hash-Baum für das Image.
  3. Erstellen Sie eine dm-verity-Tabelle für diesen Hash-Baum.
  4. Signieren Sie diese dm-verity-Tabelle, um eine Tabelle zu erstellen. Signatur.
  5. Tabellensignatur und dm-verity-Tabelle gruppieren in Verity-Metadaten um.
  6. Verketten Sie das System-Image, die Versionsmetadaten und den Hash-Baum.

Weitere Informationen finden Sie im Hilfeartikel Die Chromium-Projekte – Verifizierter Bootmodus finden Sie eine detaillierte Beschreibung des Hash-Baums und der Tabelle "dm-verity".

Hash-Struktur generieren

Wie in der Einführung beschrieben, ist der Hash-Baum ein integraler Bestandteil von dm-verity. Die cryptsetup wird einen Hash-Baum für Sie zu generieren. Alternativ wird hier eine kompatible definiert:

<your block device name> <your block device name> <block size> <block size> <image size in blocks> <image size in blocks + 8> <root hash> <salt>

Zur Bildung des Hash-Werts wird das System-Image bei Ebene 0 in 4.000 Blöcke aufgeteilt, die jeweils SHA256-Hash zugewiesen ist. Ebene 1 wird gebildet, indem nur diese SHA256-Hashes zusammengeführt werden in 4.000 Blöcke, was zu einem viel kleineren Bild führt. Ebene 2 wird gebildet identisch, mit den SHA256-Hashes der Ebene 1.

Dies geschieht, bis die SHA256-Hashes der vorherigen Ebene in ein einzelnes blockieren. Wenn Sie den SHA256-Block dieses Blocks abrufen, haben Sie den Root-Hash des Baums.

Die Größe des Hash-Baums (und die entsprechende Speicherplatznutzung) variiert je nach der verifizierten Partition an. In der Praxis ist die Größe von Hash-Bäumen klein, häufig kleiner als 30 MB.

Wenn Sie einen Block in einer Ebene haben, der nicht vollständig durch das der vorherigen Schicht haben, sollten Sie sie mit Nullen auffüllen, um 4K erwartet. So wissen Sie, dass der Hash-Baum nicht entfernt wurde stattdessen mit leeren Daten ausgefüllt.

Um den Hash-Baum zu generieren, verketten Sie die Layer-2-Hashes mit denen für die Ebene. 1, Ebene 3 die Hashes auf Ebene 2 usw. Alles aufschreiben auf die Festplatte. Beachten Sie, dass sich dies nicht auf die Ebene 0 des Root-Hashs bezieht.

Zur Erinnerung: Der allgemeine Algorithmus zum Erstellen des Hash-Baums sieht so aus:

  1. Wählen Sie nach dem Zufallsprinzip einen Salt aus (Hexadezimalcodierung).
  2. Teilen Sie Ihr System-Image in 4k-Blöcke auf.
  3. Rufen Sie für jeden Block seinen (salted) SHA256-Hash ab.
  4. Diese Hashes verketten, um eine Ebene zu bilden
  5. Füllen Sie das Level mit Nullen bis zu einer Blockgrenze von 4K.
  6. Verketten Sie die Ebene mit Ihrem Hash-Baum.
  7. Wiederholen Sie die Schritte 2 bis 6 und verwenden Sie dabei die vorherige Ebene als Quelle für die nächsten, bis haben Sie nur einen Hashwert.

Das Ergebnis ist ein einzelner Hash, Ihr Root-Hash. Das und dein Salz werden beim Erstellen der dm-verity-Zuordnungstabelle verwendet.

dm-verity-Zuordnungstabelle erstellen

Erstellen Sie die dm-verity-Zuordnungstabelle, in der das zu blockierende Gerät (oder Ziel) identifiziert wird. für den Kernel und die Position des Hash-Baums (gleicher Wert). Dieses Die Zuordnung wird für die Generierung und den Start von fstab verwendet. Die Tabelle enthält auch die Größe der Blöcke und „hash_start“, die Startposition des Hash-Baums (insbesondere die Blocknummer am Anfang des Bildes).

Unter cryptsetup finden Sie eine detaillierte Beschreibung der Felder der Tabelle für die Zuordnung der Ziele.

dm-verity-Tabelle signieren

Signieren Sie die dm-verity-Tabelle, um eine Tabellensignatur zu erstellen. Bei der Bestätigung einer wird die Tabellensignatur zuerst überprüft. Dies erfolgt anhand eines Schlüssels an einem festen Ort speichern. Schlüssel sind normalerweise im Hersteller Systeme für die automatische Integration auf Geräten in einem festen Standort.

So überprüfen Sie die Partition mit dieser Signatur-/Schlüsselkombination:

  1. Fügen Sie dem Partition /boot um /verity_key. Speicherort des für die Bestätigung verwendeten Schlüssels angeben im Hash-Baum.
  2. Fügen Sie in der fstab-Datei für den entsprechenden Eintrag verify zu den fs_mgr-Flags.

Tabellensignatur mit Metadaten bündeln

Tabellensignatur und dm-verity-Tabelle in Verity-Metadaten gruppieren. Das gesamte der Metadatenblock versioniert ist, sodass er erweitert werden kann, etwa um eine zweite Signatur oder die Reihenfolge ändern.

Zur Plausibilitätsprüfung wird jedem Satz von Tabellenmetadaten eine magische Zahl zugeordnet. anhand derer die Tabelle identifiziert werden kann. Da die Länge im ext4-System enthalten ist, kann nach den Metadaten gesucht werden, ohne zu wissen, der Daten selbst.

Dadurch wird sichergestellt, dass Sie die Prüfung einer nicht bestätigten Partition nicht ausgewählt haben. Wenn ja, wenn diese magische Zahl fehlt, wird der Bestätigungsprozess abgebrochen. Diese Nummer etwa:
0xb001b001

Die Byte-Werte im Hexadezimalformat sind:

  • erstes Byte = b0
  • zweites Byte = 01
  • drittes Byte = b0
  • viertes Byte = 01

Das folgende Diagramm zeigt eine Aufschlüsselung der Verity-Metadaten:

<magic number>|<version>|<signature>|<table length>|<table>|<padding>
\-------------------------------------------------------------------/
\----------------------------------------------------------/   |
                            |                                  |
                            |                                 32K
                       block content

In dieser Tabelle werden diese Metadatenfelder beschrieben.

Tabelle 1 Felder für Verity-Metadaten

Feld Zweck Größe Wert
Magische Zahl von fs_mgr als Integritätsprüfung verwendet 4 Byte 0xb001b001
Version zum Versionieren des Metadatenblocks 4 Byte aktuell 0
Signatur Die Signatur der Tabelle im PKCS1.5-Padding-Format 256 Byte
Tabellenlänge die Länge der dm-verity-Tabelle in Byte 4 Byte
Tisch der zuvor beschriebenen dm-verity-Tabelle Tabellenlänge in Byte
padding Diese Struktur ist auf eine Länge von 32 KB 0-aufgefüllt 0

dm-verity optimieren

Um die beste Leistung mit dm-verity zu erzielen, sollten Sie Folgendes tun:

  • Aktivieren Sie im Kernel NEON SHA-2 für ARMv7 und SHA-2 Erweiterungen für ARMv8.
  • Experimentieren Sie mit verschiedenen „read-ahead“- und „prefetch_cluster“-Clustern. Einstellungen, um die beste Konfiguration für Ihr Gerät zu finden.