Härtung des Mediengerüsts

Mit Sammlungen den Überblick behalten Sie können Inhalte basierend auf Ihren Einstellungen speichern und kategorisieren.

Um die Gerätesicherheit zu verbessern, bricht Android 7.0 den monolithischen mediaserver -Prozess in mehrere Prozesse auf, wobei die Berechtigungen und Fähigkeiten auf die für jeden Prozess erforderlichen beschränkt sind. Diese Änderungen mindern die Sicherheitslücken des Medien-Frameworks durch:

  • Aufteilen von AV-Pipeline-Komponenten in anwendungsspezifische Sandbox-Prozesse.
  • Aktivierung aktualisierbarer Medienkomponenten (Extraktoren, Codecs usw.).

Diese Änderungen verbessern auch die Sicherheit für Endbenutzer, indem sie den Schweregrad der meisten medienbezogenen Sicherheitslücken erheblich verringern und die Geräte und Daten der Endbenutzer schützen.

OEMs und SoC-Anbieter müssen ihre HAL- und Framework-Änderungen aktualisieren, um sie mit der neuen Architektur kompatibel zu machen. Da vom Anbieter bereitgestellter Android-Code häufig davon ausgeht, dass alles im selben Prozess ausgeführt wird, müssen Anbieter ihren Code aktualisieren, um native Handles ( native_handle ) zu übergeben, die prozessübergreifend von Bedeutung sind. Eine Referenzimplementierung von Änderungen im Zusammenhang mit der Medienhärtung finden Sie unter frameworks/av und frameworks/native .

Architektonische Veränderungen

Frühere Versionen von Android verwendeten einen einzigen, monolithischen mediaserver -Prozess mit vielen Berechtigungen (Kamerazugriff, Audiozugriff, Zugriff auf Videotreiber, Dateizugriff, Netzwerkzugriff usw.). Android 7.0 teilt den mediaserver Prozess in mehrere neue Prozesse auf, die jeweils einen viel kleineren Satz an Berechtigungen erfordern:

Mediaserver-Härtung

Abbildung 1. Architekturänderungen für Mediaserver-Härtung

Diese neue Architektur stellt sicher, dass bösartiger Code selbst dann, wenn ein Prozess kompromittiert wird, keinen Zugriff auf alle zuvor von Mediaserver gehaltenen Berechtigungen hat. Prozesse werden durch SElinux- und seccomp-Richtlinien eingeschränkt.

Hinweis: Aufgrund von Herstellerabhängigkeiten laufen einige Codecs immer noch auf dem mediaserver und gewähren dem mediaserver folglich mehr Berechtigungen als nötig. Konkret läuft Widevine Classic weiterhin im mediaserver für Android 7.0.

MediaServer-Änderungen

In Android 7.0 existiert der mediaserver -Prozess zum Steuern von Wiedergabe und Aufzeichnung, z. B. zum Übergeben und Synchronisieren von Puffern zwischen Komponenten und Prozessen. Prozesse kommunizieren über den standardmäßigen Binder-Mechanismus.

In einer standardmäßigen lokalen Dateiwiedergabesitzung übergibt die Anwendung einen Dateideskriptor (FD) an den mediaserver (normalerweise über die MediaPlayer-Java-API) und den mediaserver :

  1. Verpackt das FD in ein Binder DataSource-Objekt, das an den Extraktionsprozess übergeben wird, der es verwendet, um mit Binder IPC aus der Datei zu lesen. (Der Medienextrahierer ruft die FD nicht ab, sondern führt stattdessen Binder-Rückrufe an den mediaserver durch, um die Daten abzurufen.)
  2. Untersucht die Datei, erstellt den geeigneten Extraktor für den Dateityp (z. B. MP3Extractor oder MPEG4Extractor) und gibt eine Binder-Schnittstelle für den Extraktor an den mediaserver -Prozess zurück.
  3. Führt Binder IPC-Aufrufe an den Extraktor durch, um den Datentyp in der Datei zu bestimmen (z. B. MP3- oder H.264-Daten).
  4. Ruft den mediacodec Prozess auf, um Codecs des erforderlichen Typs zu erstellen; erhält Binder-Schnittstellen für diese Codecs.
  5. Führt wiederholt Binder IPC-Aufrufe an den Extraktor durch, um codierte Samples zu lesen, verwendet den Binder IPC, um codierte Daten zum Decodieren an den mediacodec Prozess zu senden, und empfängt decodierte Daten.

In einigen Anwendungsfällen ist kein Codec beteiligt (z. B. eine ausgelagerte Wiedergabe, bei der codierte Daten direkt an das Ausgabegerät gesendet werden), oder der Codec kann die decodierten Daten direkt rendern, anstatt einen Puffer mit decodierten Daten zurückzugeben (Videowiedergabe).

MediaCodecService-Änderungen

Der Codec-Dienst ist der Ort, an dem Encoder und Decoder leben. Aufgrund von Herstellerabhängigkeiten leben noch nicht alle Codecs im Codec-Prozess. Unter Android 7.0:

  • Unsichere Decoder und Software-Encoder leben im Codec-Prozess.
  • Sichere Decoder und Hardware-Encoder leben im mediaserver (unverändert).

Eine Anwendung (oder ein Medienserver) ruft den Codec-Prozess auf, um einen Codec des erforderlichen Typs zu erstellen, und ruft dann diesen Codec auf, um codierte Daten zu übergeben und decodierte Daten abzurufen (zum Decodieren) oder um decodierte Daten zu übergeben und codierte Daten abzurufen (zum Codieren). . Die Datenübertragung zu und von Codecs verwendet bereits gemeinsam genutzten Speicher, sodass dieser Prozess unverändert bleibt.

MediaDrmServer-Änderungen

Der DRM-Server wird verwendet, wenn DRM-geschützte Inhalte wie Filme in Google Play Movies wiedergegeben werden. Es entschlüsselt die verschlüsselten Daten auf sichere Weise und hat daher Zugriff auf Zertifikate und Schlüsselspeicher und andere sensible Komponenten. Aufgrund von Herstellerabhängigkeiten wird der DRM-Prozess noch nicht in allen Fällen verwendet.

AudioServer-Änderungen

Der AudioServer-Prozess hostet audiobezogene Komponenten wie Audioeingabe und -ausgabe, den policymanager-Dienst, der das Audiorouting festlegt, und den FM-Radiodienst. Einzelheiten zu Audioänderungen und Implementierungsanleitungen finden Sie unter Implementieren von Audio .

CameraServer ändert sich

Der CameraServer steuert die Kamera und wird beim Aufzeichnen von Videos verwendet, um Videoframes von der Kamera zu erhalten und sie dann zur weiteren Verarbeitung an den mediaserver weiterzuleiten. Einzelheiten zu Änderungen und Implementierungsanleitungen für CameraServer-Änderungen finden Sie unter Camera Framework Hardening .

ExtractorService-Änderungen

Der Extractor-Dienst hostet die Extractors , Komponenten, die die verschiedenen Dateiformate parsen, die vom Medien-Framework unterstützt werden. Der Extraktionsdienst ist der am wenigsten privilegierte aller Dienste – er kann keine FDs lesen, also ruft er stattdessen eine Binder-Schnittstelle (die ihm vom mediaserver for jede Wiedergabesitzung bereitgestellt wird) auf, um auf Dateien zuzugreifen.

Eine Anwendung (oder mediaserver ) ruft den Extraktionsprozess auf, um einen IMediaExtractor zu erhalten, ruft diesen IMediaExtractor auf, um IMediaSources für den in der Datei enthaltenen Titel zu erhalten, und ruft dann IMediaSources auf, um Daten daraus zu lesen.

Um die Daten zwischen Prozessen zu übertragen, fügt die Anwendung (oder der mediaserver ) die Daten in das Antwortpaket als Teil der Binder-Transaktion ein oder verwendet einen gemeinsamen Speicher:

  • Die Verwendung von Shared Memory erfordert einen zusätzlichen Binder-Aufruf, um den Shared Memory freizugeben, ist aber schneller und verbraucht weniger Energie für große Puffer.
  • Die Verwendung von In-Parcel erfordert zusätzliches Kopieren, ist aber schneller und verbraucht weniger Strom für Puffer kleiner als 64 KB.

Implementierung

Um die Verschiebung von MediaDrm und MediaCrypto Komponenten in den neuen mediadrmserver Prozess zu unterstützen, müssen Anbieter die Zuweisungsmethode für sichere Puffer ändern, damit Puffer zwischen Prozessen gemeinsam genutzt werden können.

In früheren Android-Versionen werden sichere Puffer in mediaserver von OMX::allocateBuffer und während der Entschlüsselung im selben Prozess verwendet, wie unten gezeigt:

Abbildung 2. Android 6.0 und niedrigere Pufferzuweisung im Mediaserver.

In Android 7.0 wurde der Pufferzuweisungsprozess in einen neuen Mechanismus geändert, der Flexibilität bietet und gleichzeitig die Auswirkungen auf vorhandene Implementierungen minimiert. Bei MediaDrm und MediaCrypto Stacks im neuen mediadrmserver Prozess werden Puffer unterschiedlich zugewiesen, und Anbieter müssen die sicheren Puffer-Handles aktualisieren, damit sie über den Binder transportiert werden können, wenn MediaCodec einen Entschlüsselungsvorgang für MediaCrypto .

Abbildung 3. Android 7.0 und höher Pufferzuweisung im Medienserver.

Verwendung nativer Handles

Der OMX::allocateBuffer muss einen Zeiger auf eine native_handle Struktur zurückgeben, die Dateideskriptoren (FDs) und zusätzliche Integer-Daten enthält. Ein native_handle bietet alle Vorteile der Verwendung von FDs, einschließlich vorhandener Bindeunterstützung für die Serialisierung/Deserialisierung, und bietet gleichzeitig mehr Flexibilität für Anbieter, die derzeit keine FDs verwenden.

Verwenden Sie native_handle_create() , um das native Handle zuzuweisen. Framework-Code übernimmt die Eigentümerschaft der zugewiesenen native_handle Struktur und ist verantwortlich für die Freigabe von Ressourcen sowohl in dem Prozess, in dem das native_handle ursprünglich zugewiesen wird, als auch in dem Prozess, in dem es deserialisiert wird. Das Framework gibt native Handles mit native_handle_close() gefolgt von native_handle_delete() und serialisiert/deserialisiert das native_handle mit Parcel::writeNativeHandle()/readNativeHandle() .

SoC-Anbieter, die FDs verwenden, um sichere Puffer darzustellen, können den FD im native_handle mit ihrem FD füllen. Anbieter, die keine FDs verwenden, können sichere Puffer mithilfe zusätzlicher Felder in native_buffer .

Entschlüsselungsort festlegen

Anbieter müssen die OEMCrypto-Entschlüsselungsmethode aktualisieren, die auf dem native_handle , um alle anbieterspezifischen Operationen auszuführen, die erforderlich sind, um das native_handle im neuen Prozessbereich verwendbar zu machen (Änderungen beinhalten typischerweise Aktualisierungen der OEMCrypto-Bibliotheken).

Da allocateBuffer eine standardmäßige OMX-Operation ist, enthält Android 7.0 eine neue OMX-Erweiterung ( OMX.google.android.index.allocateNativeHandle ) zum Abfragen dieser Unterstützung und einen OMX_SetParameter -Aufruf, der die OMX-Implementierung benachrichtigt, dass sie native Handles verwenden soll.