Stärkung des Medien-Frameworks

Um die Gerätesicherheit zu verbessern, unterteilt Android 7.0 den monolithischen mediaserver Prozess in mehrere Prozesse, wobei die Berechtigungen und Funktionen auf die für jeden Prozess erforderlichen Berechtigungen beschränkt sind. Diese Änderungen verringern Sicherheitslücken im Medien-Framework durch:

  • Aufteilen von AV-Pipeline-Komponenten in anwendungsspezifische Sandbox-Prozesse.
  • Aktivieren 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 Sicherheit von Endbenutzergeräten und -daten gewährleisten.

OEMs und SoC-Anbieter müssen ihre HAL- und Framework-Änderungen aktualisieren, um sie mit der neuen Architektur kompatibel zu machen. Da der von Anbietern bereitgestellte Android-Code häufig davon ausgeht, dass alles im selben Prozess ausgeführt wird, müssen Anbieter insbesondere ihren Code aktualisieren, um native Handles ( native_handle ) weiterzugeben, 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 Android-Versionen verwendeten einen einzigen, monolithischen mediaserver mit zahlreichen Berechtigungen (Kamerazugriff, Audiozugriff, Videotreiberzugriff, Dateizugriff, Netzwerkzugriff usw.). Android 7.0 teilt den mediaserver Prozess in mehrere neue Prozesse auf, die jeweils einen viel kleineren Satz an Berechtigungen erfordern:

Härtung des Medienservers

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

Diese neue Architektur stellt sicher, dass bösartiger Code selbst dann, wenn ein Prozess kompromittiert wird, keinen Zugriff auf den gesamten Satz von Berechtigungen hat, der zuvor von mediaserver gehalten wurde. Prozesse werden durch SElinux- und Seccomp-Richtlinien eingeschränkt.

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

MediaServer-Änderungen

In Android 7.0 gibt es den mediaserver Prozess zum Steuern der Wiedergabe und Aufzeichnung, z. B. zum Übergeben und Synchronisieren von Puffern zwischen Komponenten und Prozessen. Prozesse kommunizieren über den Standard-Binder-Mechanismus.

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

  1. Wickelt das FD in ein Binder DataSource-Objekt ein, das an den Extraktionsprozess übergeben wird, der es zum Lesen aus der Datei mithilfe von Binder IPC verwendet. (Der MediaExtractor ruft den FD nicht ab, sondern führt stattdessen Binder-Aufrufe zurück an den mediaserver , um die Daten abzurufen.)
  2. Untersucht die Datei, erstellt den entsprechenden 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 wiederholte Binder-IPC-Aufrufe an den Extraktor durch, um codierte Proben zu lesen, verwendet den Binder-IPC, um codierte Daten zur Decodierung an den mediacodec Prozess zu senden, und empfängt decodierte Daten.

In einigen Anwendungsfällen ist kein Codec beteiligt (z. B. bei einer Offloaded-Wiedergabe, bei der codierte Daten direkt an das Ausgabegerät gesendet werden), oder der Codec rendert die decodierten Daten möglicherweise direkt, 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 sind noch nicht alle Codecs im Codec-Prozess aktiv. In Android 7.0:

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

Eine App (oder mediaserver ) 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 (zur Decodierung) oder um decodierte Daten zu übergeben und codierte Daten abzurufen (zur Codierung). . Die Datenübertragung zu und von Codecs nutzt bereits gemeinsam genutzten Speicher, sodass dieser Prozess unverändert bleibt.

MediaDrmServer ändert sich

Der DRM-Server wird bei der Wiedergabe von DRM-geschützten Inhalten wie Filmen in Google Play Movies verwendet. Es übernimmt die sichere Entschlüsselung der verschlüsselten Daten und hat somit Zugriff auf den Zertifikats- und Schlüsselspeicher sowie andere sensible Komponenten. Aufgrund von Herstellerabhängigkeiten wird das DRM-Verfahren noch nicht in allen Fällen eingesetzt.

AudioServer-Änderungen

Der AudioServer-Prozess hostet audiobezogene Komponenten wie Audio-Eingabe und -Ausgabe, den Policymanager-Dienst, der das Audio-Routing bestimmt, und den UKW-Radiodienst. Einzelheiten zu Audioänderungen und Implementierungsanleitungen finden Sie unter Implementieren von Audio .

CameraServer-Änderungen

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

ExtractorService-Änderungen

Der Extraktordienst hostet die Extraktoren , Komponenten, die die verschiedenen vom Medienframework unterstützten Dateiformate analysieren. Der Extraktionsdienst ist der Dienst mit den geringsten Privilegien – er kann keine FDs lesen und ruft daher stattdessen eine Binder-Schnittstelle auf (die ihm vom mediaserver for jede Wiedergabesitzung bereitgestellt wird), um auf Dateien zuzugreifen.

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

Um die Daten zwischen Prozessen zu übertragen, bindet die App (oder mediaserver ) die Daten im Rahmen der Binder-Transaktion in das Antwortpaket ein oder nutzt den gemeinsamen Speicher:

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

Implementierung

Um die Verlagerung von MediaDrm und MediaCrypto Komponenten in den neuen mediadrmserver Prozess zu unterstützen, müssen Anbieter die Zuweisungsmethode für sichere Puffer ändern, um die gemeinsame Nutzung von Puffern zwischen Prozessen zu ermöglichen.

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

Abbildung 2. Android 6.0 und niedrigere Pufferzuordnung im Mediaserver.

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

Abbildung 3. Pufferzuordnung für Android 7.0 und höher im Mediaserver.

Verwenden Sie native Handles

Der OMX::allocateBuffer muss einen Zeiger auf eine native_handle Struktur zurückgeben, die Dateideskriptoren (FDs) und zusätzliche Ganzzahldaten enthält. Ein native_handle bietet alle Vorteile der Verwendung von FDs, einschließlich der vorhandenen Binder-Unterstützung für 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. Der Framework-Code übernimmt den Besitz der zugewiesenen native_handle Struktur und ist für die Freigabe von Ressourcen sowohl in dem Prozess, in dem der native_handle ursprünglich zugewiesen wurde, als auch in dem Prozess, in dem er deserialisiert wird, verantwortlich. Das Framework gibt native Handles mit native_handle_close() gefolgt von native_handle_delete() frei und serialisiert/deserialisiert das native_handle mithilfe von Parcel::writeNativeHandle()/readNativeHandle() .

SoC-Anbieter, die FDs zur Darstellung sicherer Puffer verwenden, können das FD im native_handle mit ihrem FD füllen. Anbieter, die keine FDs verwenden, können sichere Puffer mithilfe zusätzlicher Felder im native_buffer darstellen.

Legen Sie den Ort für die Entschlüsselung fest

Anbieter müssen die OEMCrypto-Entschlüsselungsmethode aktualisieren, die auf dem native_handle ausgeführt wird, um alle herstellerspezifischen Vorgänge auszuführen, die erforderlich sind, um das native_handle im neuen Prozessraum nutzbar zu machen (Änderungen umfassen normalerweise 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 ), um diese Unterstützung abzufragen, und einen OMX_SetParameter Aufruf, der die OMX-Implementierung benachrichtigt, dass sie native Handles verwenden soll.