Härtung von Medienframeworks

Zur Verbesserung der Gerätesicherheit wird der monolithische mediaserver-Prozess in Android 7.0 in mehrere Prozesse aufgeteilt, deren Berechtigungen und Funktionen auf die für jeden Prozess erforderlichen beschränkt sind. Durch diese Änderungen werden Sicherheitslücken im Media Framework minimiert:

  • Die Komponenten der Antiviren-Pipeline in appspezifische Prozesse in einer Sandbox aufteilen.
  • Aktivieren von aktualisierbaren Medienkomponenten (Extractor, Codecs usw.)

Diese Änderungen verbessern auch die Sicherheit für Endnutzer, da die meisten medienbezogenen Sicherheitslücken erheblich reduziert werden und so die Geräte und Daten der Endnutzer geschützt werden.

OEMs und SoC-Anbieter müssen ihre HAL- und Framework-Änderungen aktualisieren, damit sie mit der neuen Architektur kompatibel sind. Da der von Anbietern bereitgestellte 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 für alle Prozesse relevant sind. Eine Referenzimplementierung der Änderungen im Zusammenhang mit der Medienhärtung findest du unter frameworks/av und frameworks/native.

Architekturänderungen

In früheren Android-Versionen wurde ein einzelner monolithischer mediaserver-Prozess mit sehr vielen Berechtigungen verwendet (z. B. Kamerazugriff, Audiozugriff, Videotreiberzugriff, Dateizugriff, Netzwerkzugriff). Unter Android 7.0 wird der mediaserver-Prozess in mehrere neue Prozesse aufgeteilt, für die jeweils deutlich weniger Berechtigungen erforderlich sind:

Mediaserver-Härtung

Abbildung 1: Architekturänderungen zur Medienserver-Härtung

Diese neue Architektur sorgt dafür, dass schädlicher Code auch dann nicht auf die gesamten Berechtigungen zugreifen kann, die zuvor von mediaserver gehalten wurden, wenn ein Prozess manipuliert wird. Prozesse werden durch SELinux- und Seccomp-Richtlinien eingeschränkt.

Hinweis:Aufgrund von Anbieterabhängigkeiten werden einige Codecs weiterhin im mediaserver ausgeführt und gewähren ihm daher mehr Berechtigungen als erforderlich.mediaserver Insbesondere wird Widevine Classic weiterhin in der mediaserver für Android 7.0 ausgeführt.

Änderungen am MediaServer

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

Bei einer Standardwiedergabesitzung lokaler Dateien übergibt die App einen Dateideskriptor (File Descriptor, FD) an mediaserver (in der Regel über die MediaPlayer Java API). mediaserver:

  1. Umschließt den Dateideskriptor in ein Binder-Datenquellenobjekt, das an den Extraktionsprozess übergeben wird, der damit Daten über Binder IPC aus der Datei liest. (Der mediaextractor ruft die FD nicht ab, sondern sendet Binderaufrufe an die mediaserver, um die Daten abzurufen.)
  2. Prüft die Datei, erstellt den entsprechenden Extractor für den Dateityp (z.B. MP3Extractor oder MPEG4Extractor) und gibt eine Binder-Oberfläche für den Extractor an den mediaserver-Prozess zurück.
  3. Er führt Binder-IPC-Aufrufe an den Extractor aus, um den Datentyp in der Datei zu ermitteln (z.B. MP3- oder H.264-Daten).
  4. Ruft den mediacodec-Prozess auf, um Codecs des erforderlichen Typs zu erstellen, und empfängt Binder-Schnittstellen für diese Codecs.
  5. Führt wiederholte Binder-IPC-Aufrufe an den Extractor aus, um codierte Samples zu lesen, und verwendet den Binder-IPC, um codierte Daten zur Dekodierung an den mediacodec-Prozess zu senden. Außerdem werden decodierte Daten empfangen.

In einigen Anwendungsfällen kommt kein Codec zum Einsatz (z. B. bei einer ausgelagerten Wiedergabe, bei der codierte Daten direkt an das Ausgabegerät gesendet werden). Der Codec kann die decodierten Daten auch direkt rendern, anstatt einen Puffer mit decodierten Daten zurückzugeben (Videowiedergabe).

Änderungen am MediaCodecService

Der Codec-Dienst ist der Ort, an dem Encoder und Decoder zu finden sind. Aufgrund von Anbieterabhängigkeiten sind noch nicht alle Codecs im Codec-Prozess verfügbar. Unter Android 7.0:

  • Nicht sichere Decoder und Software-Encoder werden im Codec-Prozess ausgeführt.
  • Sichere Dekoder und Hardware-Encoder befinden sich in der 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 einzugeben und decodierte Daten abzurufen (für die Dekodierung) oder decodierte Daten einzugeben und codierte Daten abzurufen (für die Codierung). Für die Datenübertragung zu und von Codecs wird bereits gemeinsam genutzter Arbeitsspeicher verwendet. Dieser Vorgang bleibt also unverändert.

Änderungen bei MediaDrmServer

Der DRM-Server wird beim Abspielen von DRM-geschützten Inhalten wie Filmen in Google Play Filme & Serien verwendet. Es sorgt für eine sichere Entschlüsselung der verschlüsselten Daten und hat daher Zugriff auf Zertifikats- und Schlüsselspeicher sowie andere sensible Komponenten. Aufgrund von Anbieterabhängigkeiten wird der DRM-Prozess noch nicht in allen Fällen verwendet.

Änderungen am AudioServer

Der AudioServer-Prozess beherbergt audiobezogene Komponenten wie Audioeingabe und ‑ausgabe, den PolicyManager-Dienst, der die Audio-Routing-Funktion bestimmt, und den FM-Radiodienst. Weitere Informationen zu den Änderungen am Audio und zur Implementierung finden Sie unter Audio implementieren.

Änderungen am CameraServer

Der CameraServer steuert die Kamera und wird bei der Videoaufzeichnung verwendet, um Videoframes von der Kamera abzurufen und dann zur weiteren Verarbeitung an mediaserver weiterzuleiten. Weitere Informationen zu den Änderungen und Implementierungsanleitungen für CameraServer-Änderungen finden Sie unter Camera Framework-Härtung.

Änderungen an ExtractorService

Der Extractor-Dienst beherbergt die Extractor, Komponenten, die die verschiedenen vom Media-Framework unterstützten Dateiformate parsen. Der Extractor-Dienst hat die geringsten Berechtigungen aller Dienste. Er kann keine FDs lesen und ruft stattdessen eine Binder-Schnittstelle auf, die ihm von der mediaserver for für jede Wiedergabesitzung zur Verfügung gestellt wird, um auf Dateien zuzugreifen.

Eine App (oder mediaserver) ruft den Extraktionsprozess auf, um eine IMediaExtractor abzurufen, ruft diese 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, fügt die App (oder mediaserver) die Daten als Teil der Binder-Transaktion in das Antwort-Parcel ein oder verwendet gemeinsamen Speicher:

  • Die Verwendung von freigegebenem Arbeitsspeicher erfordert einen zusätzlichen Binder-Aufruf, um den freigegebenen Arbeitsspeicher freizugeben. Sie ist jedoch schneller und verbraucht bei großen Puffern weniger Strom.
  • Die Verwendung von In-Parcel erfordert zusätzliches Kopieren, ist aber schneller und verbraucht bei Puffern unter 64 KB weniger Strom.

Implementierung

Um die Migration 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 freigegeben werden können.

In früheren Android-Releases werden sichere Buffers in mediaserver durch OMX::allocateBuffer zugewiesen und während der Entschlüsselung im selben Prozess verwendet, wie unten dargestellt:

Abbildung 2: Pufferzuweisung im Mediaserver unter Android 6.0

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 übertragen werden können, wenn MediaCodec einen Entschlüsselungsvorgang auf MediaCrypto auslöst.

Abbildung 3: Pufferzuweisung im Mediaserver unter Android 7.0 und höher

Native Aliasse verwenden

OMX::allocateBuffer muss einen Verweis auf ein native_handle-Struktur zurückgeben, das Dateideskriptoren (FDs) und zusätzliche Ganzzahldaten enthält. Ein native_handle bietet alle Vorteile der Verwendung von FDs, einschließlich der vorhandenen Binderunterstü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 den nativen Handle zuzuweisen. Der Framework-Code übernimmt die Inhaberschaft für das zugewiesene native_handle-Objekt und ist dafür verantwortlich, Ressourcen sowohl im Prozess, in dem native_handle ursprünglich zugewiesen wird, als auch im Prozess, in dem es deserialisiert wird, freizugeben. Das Framework gibt native Handles mit native_handle_close() gefolgt von native_handle_delete() frei und serialisiert/deserialisiert die native_handle mit Parcel::writeNativeHandle()/readNativeHandle().

SoC-Anbieter, die FDs zum Darstellen sicherer Puffer verwenden, können den FD in der native_handle mit ihrem FD ausfüllen. Anbieter, die keine FDs verwenden, können sichere Puffer mithilfe zusätzlicher Felder in der native_buffer darstellen.

Ort der Entschlüsselung festlegen

Anbieter müssen die OEMCrypto-Entschlüsselungsmethode aktualisieren, die auf der native_handle ausgeführt wird, um alle anbieterspezifischen Vorgänge auszuführen, die erforderlich sind, um die native_handle im neuen Prozessbereich nutzbar zu machen. Zu den Änderungen gehören in der Regel Aktualisierungen der OEMCrypto-Bibliotheken.

Da allocateBuffer eine Standard-OMX-Operation ist, enthält Android 7.0 eine neue OMX-Erweiterung (OMX.google.android.index.allocateNativeHandle), um nach dieser Unterstützung zu fragen, und einen OMX_SetParameter-Aufruf, der die OMX-Implementierung darüber informiert, dass native Handles verwendet werden sollen.