Pour améliorer la sécurité des appareils, Android 7.0 divise le processus monolithique mediaserver
en plusieurs processus avec des autorisations et des capacités limitées à celles requises par chaque processus. Ces changements atténuent les vulnérabilités de sécurité du cadre multimédia en :
- Diviser les composants du pipeline AV en processus sandbox spécifiques à l'application.
- Activation des composants multimédias pouvant être mis à jour (extracteurs, codecs, etc.).
Ces changements améliorent également la sécurité des utilisateurs finaux en réduisant considérablement la gravité de la plupart des vulnérabilités de sécurité liées aux médias, garantissant ainsi la sécurité des appareils et des données des utilisateurs finaux.
Les OEM et les fournisseurs de SoC doivent mettre à jour leurs modifications HAL et framework pour les rendre compatibles avec la nouvelle architecture. Plus précisément, étant donné que 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 les descripteurs natifs ( native_handle
) qui ont une signification à travers les processus. Pour une implémentation de référence des modifications liées au renforcement des médias, reportez-vous à frameworks/av
et frameworks/native
.
Changements architecturaux
Les versions précédentes d'Android utilisaient un processus mediaserver
unique et monolithique avec de 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 d'autorisations beaucoup plus restreint :
Cette nouvelle architecture garantit que même si un processus est compromis, le code malveillant n'a pas accès à l'ensemble complet des autorisations précédemment détenues par mediaserver
. Les processus sont limités par les politiques SElinux et seccomp.
Remarque : En raison des dépendances du fournisseur, certains codecs s'exécutent toujours sur le mediaserver
et accordent par conséquent mediaserver
plus d'autorisations que nécessaire. Plus précisément, Widevine Classic continue de fonctionner sur le mediaserver
pour Android 7.0.
Modifications du serveur multimédia
Dans Android 7.0, le processus mediaserver
existe pour piloter la lecture et l'enregistrement, par exemple en passant et en synchronisant les tampons entre les composants et les processus. Les processus communiquent via le mécanisme standard de Binder.
Dans une session de lecture de fichier locale standard, l'application transmet un descripteur de fichier (FD) au mediaserver
(généralement via l'API Java MediaPlayer) et au mediaserver
:
- Encapsule le FD dans un objet Binder DataSource qui est transmis au processus d'extraction, qui l'utilise pour lire le fichier à l'aide de Binder IPC. (Le mediaextractor ne récupère pas le FD mais renvoie à la place 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 Binder IPC à l'extracteur pour déterminer le type de données dans le fichier (par exemple, données MP3 ou H.264).
- Appelle le processus
mediacodec
pour créer les codecs du type requis ; reçoit les interfaces Binder pour ces codecs. - Effectue des appels répétés du Binder IPC à l'extracteur pour lire des échantillons codés, utilise le Binder IPC pour envoyer des données codées au processus
mediacodec
pour le décodage et reçoit les données décodées.
Dans certains cas d'utilisation, aucun codec n'est impliqué (comme une lecture déchargée où les données codées sont envoyées directement au périphérique de sortie), ou le codec peut restituer les données décodées directement au lieu de renvoyer un tampon de données décodées (lecture vidéo).
Modifications de MediaCodecService
Le service de codec est l'endroit où vivent les encodeurs et les décodeurs. En raison des dépendances des fournisseurs, tous les codecs ne sont pas encore intégrés au processus de codec. Sous Android 7.0 :
- Les décodeurs et encodeurs logiciels non sécurisés vivent dans le processus de codec.
- Les décodeurs sécurisés et les encodeurs matériels résident dans le
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 codé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 codées (pour le codage). . Le transfert de données vers et depuis les codecs utilise déjà la mémoire partagée, ce processus reste donc inchangé.
Modifications de MediaDrmServer
Le serveur DRM est utilisé lors de la lecture de contenu protégé par DRM, tel que des films dans Google Play Movies. Il gère le décryptage des données cryptées de manière sécurisée et, en tant que tel, a accès au stockage des certificats et des clés ainsi qu'à d'autres composants sensibles. En raison des dépendances vis-à-vis des fournisseurs, le processus DRM n'est pas encore utilisé dans tous les cas.
Modifications du serveur Audio
Le processus AudioServer héberge des composants liés à l'audio tels que l'entrée et la sortie audio, le service PolicyManager qui détermine le routage audio et le service radio FM. Pour plus de détails sur les modifications audio et les conseils de mise en œuvre, consultez Implémenter l’audio .
Modifications de CameraServer
Le 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 au mediaserver
pour un traitement ultérieur. Pour plus de détails sur les modifications et les conseils de mise en œuvre des modifications apportées à CameraServer, reportez-vous à Camera Framework Hardening .
Modifications du service Extractor
Le service d'extraction héberge les extracteurs , composants qui analysent les différents formats de fichiers pris en charge par 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 appelle donc une interface Binder (qui lui est fournie par le 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 IMediaSources
pour la piste contenue dans le fichier, puis appelle IMediaSources
pour en lire les données.
Pour transférer les données entre les processus, l'application (ou mediaserver
) inclut les données dans la réponse-Parcel dans le cadre de la transaction Binder 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 tampons volumineux.
- L'utilisation d'in-Parcel nécessite une copie supplémentaire mais est plus rapide et consomme moins d'énergie pour les tampons inférieurs à 64 Ko.
Mise en œuvre
Pour prendre en charge le déplacement 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 le partage des tampons 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écryptage dans le même processus, comme indiqué ci-dessous :
Dans Android 7.0, le processus d'allocation de tampon a été remplacé par un nouveau mécanisme offrant de la 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 descripteurs de tampon sécurisé afin qu'ils puissent être transportés à travers le classeur lorsque MediaCodec
appelle une opération de décryptage sur MediaCrypto
.
Utiliser des handles natifs
OMX::allocateBuffer
doit renvoyer un pointeur vers une structure native_handle
, qui contient des descripteurs de fichiers (FD) et des données entières supplémentaires. Un native_handle
présente tous les avantages de l'utilisation des FD, y compris la prise en charge existante des classeurs pour la sérialisation/désérialisation, tout en offrant plus de flexibilité aux fournisseurs qui n'utilisent pas actuellement les FD.
Utilisez native_handle_create()
pour allouer le handle natif. Le code framework s'approprie la structure native_handle
allouée et est responsable de la libération des ressources à la fois dans le processus où le native_handle
est initialement alloué et dans le processus où il est désérialisé. Le framework publie des handles natifs 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 remplir le FD dans native_handle
avec leur FD. Les fournisseurs qui n'utilisent pas de FD peuvent représenter des tampons sécurisés en utilisant des champs supplémentaires dans native_buffer
.
Définir l'emplacement de décryptage
Les fournisseurs doivent mettre à jour la méthode de décryptage OEMCrypto qui fonctionne sur native_handle
pour effectuer toutes les opérations spécifiques au fournisseur nécessaires pour rendre le 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 handles natifs.