Pour améliorer la sécurité de l'appareil, Android 7.0 divise le processus monolithique mediaserver
en plusieurs processus dont les autorisations et les fonctionnalités sont limitées aux seules requises par chaque processus. Ces modifications atténuent les failles de sécurité du framework multimédia en:
- Divisez les composants du pipeline AV en processus en bac à sable spécifiques à l'application.
- Activation des composants multimédias pouvant être mis à jour (extracteurs, codecs, etc.).
Ces modifications améliorent également la sécurité pour les utilisateurs finaux en réduisant considérablement la gravité de la plupart des failles de sécurité liées aux contenus multimédias, ce qui protège les appareils et les données des utilisateurs finaux.
Les OEM et les fournisseurs de SoC doivent mettre à jour leurs modifications de HAL et de framework pour les rendre compatibles avec la nouvelle architecture. Plus précisément, comme le code Android fourni par le fournisseur suppose souvent que tout s'exécute dans le même processus, les fournisseurs doivent mettre à jour leur code pour transmettre des poignées natives (native_handle
) qui ont une signification entre les processus. Pour une implémentation de référence des modifications liées au renforcement des médias, consultez frameworks/av
et frameworks/native
.
Modifications architecturales
Les versions précédentes d'Android utilisaient un seul processus mediaserver
monolithique avec de très nombreuses autorisations (accès à la caméra, accès audio, accès au pilote vidéo, accès aux fichiers, accès au réseau, etc.). Android 7.0 divise le processus mediaserver
en plusieurs nouveaux processus qui nécessitent chacun un ensemble beaucoup plus petit d'autorisations:
Figure 1 : Modifications de l'architecture pour le renforcement du serveur multimédia
Cette nouvelle architecture garantit que, même si un processus est compromis, le code malveillant n'a pas accès à l'ensemble complet d'autorisations précédemment détenues par mediaserver
. Les processus sont limités par les règles SELinux et seccomp.
Remarque:En raison des dépendances du fournisseur, certains codecs s'exécutent toujours dans mediaserver
et accordent par conséquent à mediaserver
plus d'autorisations que nécessaire. Plus précisément, Widevine Classic continue de s'exécuter dans le mediaserver
pour Android 7.0.
Modifications apportées à MediaServer
Dans Android 7.0, le processus mediaserver
existe pour piloter la lecture et l'enregistrement, par exemple pour transmettre et synchroniser des tampons entre les composants et les processus. Les processus communiquent via le mécanisme standard de liaison.
Dans une session de lecture de fichier local standard, l'application transmet un descripteur de fichier (FD) à mediaserver
(généralement via l'API Java MediaPlayer), et mediaserver
:
- Encapsule le FD dans un objet DataSource de liaison qui est transmis au processus d'extraction, qui l'utilise pour lire le fichier à l'aide de l'IPC de liaison. (Le mediaextractor n'obtient pas le FD, mais renvoie des appels Binder au
mediaserver
pour obtenir les données.) - Examine le fichier, crée l'extracteur approprié pour le type de fichier (par exemple, MP3Extractor ou MPEG4Extractor) et renvoie une interface Binder pour l'extracteur au processus
mediaserver
. - Effectue des appels IPC Binder à l'extracteur pour déterminer le type de données du fichier (par exemple, données MP3 ou H.264).
- Appels du processus
mediacodec
pour créer des codecs du type requis ; reçoit des interfaces Binder pour ces codecs. - Effectue des appels IPC Binder répétés à l'extracteur pour lire des échantillons encodés, utilise l'IPC Binder pour envoyer des données encodées au processus
mediacodec
pour le décodage et reçoit des données décodées.
Dans certains cas d'utilisation, aucun codec n'est impliqué (par exemple, une lecture hors charge où les données encodées sont envoyées directement à l'appareil de sortie), ou le codec peut afficher directement les données décodées au lieu de renvoyer un tampon de données décodées (lecture vidéo).
Modifications apportées à MediaCodecService
Le service de codec est l'emplacement des encodeurs et des décodeurs. En raison des dépendances des fournisseurs, tous les codecs ne sont pas encore disponibles dans le processus de codec. Sous Android 7.0:
- Les décodeurs et les encodeurs logiciels non sécurisés résident dans le processus de codec.
- Les décodeurs sécurisés et les encodeurs matériels se trouvent dans
mediaserver
(inchangé).
Une application (ou mediaserver
) appelle le processus de codec pour créer un codec du type requis, puis appelle ce codec pour transmettre des données encodées et récupérer des données décodées (pour le décodage) ou pour transmettre des données décodées et récupérer des données encodées (pour l'encodage). Le transfert de données vers et depuis les codecs utilise déjà la mémoire partagée. Ce processus n'est donc pas modifié.
Modifications apportées à MediaDrmServer
Le serveur DRM est utilisé lors de la lecture de contenus protégés par DRM, tels que des films dans Google Play Films. Il gère le déchiffrement des données chiffrées de manière sécurisée et a donc accès au stockage des certificats et des clés, ainsi qu'à d'autres composants sensibles. En raison des dépendances aux fournisseurs, le processus DRM n'est pas encore utilisé dans tous les cas.
Modifications apportées à AudioServer
Le processus AudioServer héberge des composants audio tels que l'entrée et la sortie audio, le service policymanager qui détermine le routage audio et le service de radio FM. Pour en savoir plus sur les modifications apportées à l'audio et obtenir des conseils d'implémentation, consultez la section Implémenter l'audio.
Modifications apportées à CameraServer
CameraServer contrôle la caméra et est utilisé lors de l'enregistrement vidéo pour obtenir des images vidéo de la caméra, puis les transmettre à mediaserver
pour une gestion ultérieure. Pour en savoir plus sur les modifications et obtenir des conseils d'implémentation pour les modifications de CameraServer, consultez la section Renforcement du framework de caméra.
Modifications apportées à ExtractorService
Le service d'extraction héberge les extracteurs, des composants qui analysent les différents formats de fichiers compatibles avec le framework multimédia. Le service d'extraction est le moins privilégié de tous les services. Il ne peut pas lire les FD. Il effectue donc des appels sur une interface Binder (fournie par mediaserver for
à chaque session de lecture) pour accéder aux fichiers.
Une application (ou mediaserver
) appelle le processus d'extraction pour obtenir un IMediaExtractor
, appelle ce IMediaExtractor
pour obtenir un IMediaSources
pour le titre contenu dans le fichier, puis appelle IMediaSources
pour lire les données.
Pour transférer les données entre les processus, l'application (ou mediaserver
) inclut les données dans le parcel de réponse dans le cadre de la transaction du liaisonneur ou utilise la mémoire partagée:
- L'utilisation de la mémoire partagée nécessite un appel Binder supplémentaire pour libérer la mémoire partagée, mais elle est plus rapide et consomme moins d'énergie pour les grands tampons.
- L'utilisation de in-Parcel nécessite des copies supplémentaires, mais est plus rapide et consomme moins d'énergie pour les tampons de moins de 64 ko.
Implémentation
Pour permettre le transfert des composants MediaDrm
et MediaCrypto
vers le nouveau processus mediadrmserver
, les fournisseurs doivent modifier la méthode d'allocation des tampons sécurisés afin de permettre leur partage entre les processus.
Dans les versions précédentes d'Android, les tampons sécurisés sont alloués dans mediaserver
par OMX::allocateBuffer
et utilisés lors du déchiffrement dans le même processus, comme illustré ci-dessous:
Figure 2. Allocation de tampon Android 6.0 et versions antérieures dans mediaserver.
Dans Android 7.0, le processus d'allocation de mémoire tampon a été remplacé par un nouveau mécanisme qui offre une flexibilité tout en minimisant l'impact sur les implémentations existantes. Avec les piles MediaDrm
et MediaCrypto
dans le nouveau processus mediadrmserver
, les tampons sont alloués différemment et les fournisseurs doivent mettre à jour les poignées de tampon sécurisées afin qu'elles puissent être transportées via le liaison lorsque MediaCodec
appelle une opération de déchiffrement sur MediaCrypto
.
Figure 3. Allocation de tampon Android 7.0 ou version ultérieure dans mediaserver.
Utiliser des identifiants natifs
OMX::allocateBuffer
doit renvoyer un pointeur vers une struct native_handle
, qui contient des descripteurs de fichiers (FD) et des données d'entier supplémentaires. Un native_handle
présente tous les avantages de l'utilisation de FD, y compris la prise en charge existante des liaisons pour la sérialisation/désérialisation, tout en offrant plus de flexibilité aux fournisseurs qui n'utilisent pas actuellement de FD.
Utilisez native_handle_create()
pour allouer le gestionnaire natif.
Le code du framework prend possession de la struct native_handle
allouée et est responsable de la libération des ressources à la fois dans le processus où l'native_handle
est initialement allouée et dans le processus où elle est désérialisée. Le framework libère des poignées natives avec native_handle_close()
, suivi de native_handle_delete()
, et sérialise/désérialise le native_handle
à l'aide de Parcel::writeNativeHandle()/readNativeHandle()
.
Les fournisseurs de SoC qui utilisent des FD pour représenter des tampons sécurisés peuvent renseigner le FD dans le native_handle
avec leur FD. Les fournisseurs qui n'utilisent pas de FD peuvent représenter des tampons sécurisés à l'aide de champs supplémentaires dans native_buffer
.
Définir l'emplacement de déchiffrement
Les fournisseurs doivent mettre à jour la méthode de déchiffrement OEMCrypto qui fonctionne sur native_handle
pour effectuer toutes les opérations spécifiques au fournisseur nécessaires pour rendre native_handle
utilisable dans le nouvel espace de processus (les modifications incluent généralement des mises à jour des bibliothèques OEMCrypto).
Comme allocateBuffer
est une opération OMX standard, Android 7.0 inclut une nouvelle extension OMX (OMX.google.android.index.allocateNativeHandle
) pour interroger cette prise en charge et un appel OMX_SetParameter
qui informe l'implémentation OMX qu'elle doit utiliser des poignées natives.