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:
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
:
- 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.) - 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. - Führt Binder-IPC-Aufrufe an den Extraktor durch, um den Datentyp in der Datei zu bestimmen (z. B. MP3- oder H.264-Daten).
- Ruft den
mediacodec
Prozess auf, um Codecs des erforderlichen Typs zu erstellen; erhält Binder-Schnittstellen für diese Codecs. - 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:
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.
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.