Indurimento della struttura dei media

Per migliorare la sicurezza del dispositivo, Android 7.0 suddivide il processo monolitico del mediaserver in più processi con autorizzazioni e funzionalità limitate solo a quelle richieste da ciascun processo. Queste modifiche attenuano le vulnerabilità della sicurezza del framework dei media:

  • Suddivisione dei componenti della pipeline AV in processi sandbox specifici dell'app.
  • Abilitazione di componenti multimediali aggiornabili (estrattori, codec, ecc.).

Queste modifiche migliorano anche la sicurezza per gli utenti finali, riducendo in modo significativo la gravità della maggior parte delle vulnerabilità di sicurezza relative ai media, mantenendo al sicuro i dispositivi e i dati degli utenti finali.

Gli OEM e i fornitori di SoC devono aggiornare i propri HAL e le modifiche al framework per renderli compatibili con la nuova architettura. In particolare, poiché il codice Android fornito dal fornitore spesso presuppone che tutto venga eseguito nello stesso processo, i fornitori devono aggiornare il proprio codice per passare gli handle nativi ( native_handle ) che hanno significato tra i processi. Per un'implementazione di riferimento delle modifiche relative al rafforzamento dei media, fare riferimento a frameworks/av e frameworks/native .

Cambiamenti architettonici

Le versioni precedenti di Android utilizzavano un unico processo mediaserver monolitico con molte autorizzazioni (accesso alla fotocamera, accesso all'audio, accesso al driver video, accesso ai file, accesso alla rete, ecc.). Android 7.0 suddivide il processo del mediaserver in diversi nuovi processi che richiedono ciascuno un insieme molto più piccolo di autorizzazioni:

indurimento del server multimediale

Figura 1. Modifiche all'architettura per la protezione avanzata del mediaserver

Questa nuova architettura garantisce che, anche se un processo è compromesso, il codice dannoso non ha accesso al set completo di autorizzazioni precedentemente detenute da mediaserver. I processi sono limitati dalle politiche di SElinux e seccomp.

Nota: a causa delle dipendenze del fornitore, alcuni codec vengono ancora eseguiti nel mediaserver e di conseguenza concedono mediaserver più autorizzazioni del necessario. In particolare, Widevine Classic continua a funzionare nel mediaserver per Android 7.0.

Il server multimediale cambia

In Android 7.0, esiste il processo mediaserver per guidare la riproduzione e la registrazione, ad esempio il passaggio e la sincronizzazione dei buffer tra componenti e processi. I processi comunicano attraverso il meccanismo Binder standard.

In una sessione di riproduzione di file locali standard, l'applicazione passa un descrittore di file (FD) a mediaserver (di solito tramite l'API Java MediaPlayer) e mediaserver :

  1. Inserisce l'FD in un oggetto DataSource Binder che viene passato al processo di estrazione, che lo usa per leggere il file usando Binder IPC. (Il mediaextractor non ottiene l'FD ma invece richiama Binder al mediaserver per ottenere i dati.)
  2. Esamina il file, crea l'estrattore appropriato per il tipo di file (ad es. MP3Extractor o MPEG4Extractor) e restituisce un'interfaccia Binder per l'estrattore al processo mediaserver .
  3. Effettua chiamate IPC Binder all'estrattore per determinare il tipo di dati nel file (es. dati MP3 o H.264).
  4. Richiama al processo mediacodec per creare codec del tipo richiesto; riceve le interfacce Binder per questi codec.
  5. Effettua ripetute chiamate Binder IPC all'estrattore per leggere campioni codificati, utilizza Binder IPC per inviare dati codificati al processo mediacodec per la decodifica e riceve dati decodificati.

In alcuni casi d'uso, non è coinvolto alcun codec (come una riproduzione scaricata in cui i dati codificati vengono inviati direttamente al dispositivo di output), oppure il codec può eseguire il rendering dei dati decodificati direttamente invece di restituire un buffer di dati decodificati (riproduzione video).

Modifiche al servizio MediaCodec

Il servizio codec è il luogo in cui risiedono codificatori e decodificatori. A causa delle dipendenze del fornitore, non tutti i codec sono ancora attivi nel processo di codec. In Android 7.0:

  • Decoder non sicuri e codificatori software risiedono nel processo di codec.
  • Decoder sicuri e codificatori hardware risiedono nel mediaserver (invariato).

Un'applicazione (o mediaserver) chiama il processo del codec per creare un codec del tipo richiesto, quindi chiama quel codec per trasmettere i dati codificati e recuperare i dati decodificati (per la decodifica) o per trasmettere i dati decodificati e recuperare i dati codificati (per la codifica) . Il trasferimento di dati da e verso i codec utilizza già la memoria condivisa, quindi il processo rimane invariato.

Modifiche a MediaDrmServer

Il server DRM viene utilizzato durante la riproduzione di contenuti protetti da DRM, come i film in Google Play Movies. Gestisce la decrittografia dei dati crittografati in modo sicuro e, in quanto tale, ha accesso all'archiviazione di certificati e chiavi e ad altri componenti sensibili. A causa delle dipendenze del fornitore, il processo DRM non viene ancora utilizzato in tutti i casi.

Cambia il server audio

Il processo AudioServer ospita componenti relativi all'audio come input e output audio, il servizio policymanager che determina l'instradamento audio e il servizio radio FM. Per i dettagli sulle modifiche all'audio e la guida all'implementazione, vedere Implementazione dell'audio .

Cambia CameraServer

Il CameraServer controlla la telecamera e viene utilizzato durante la registrazione di video per ottenere fotogrammi video dalla telecamera e quindi passarli al mediaserver per un'ulteriore gestione. Per i dettagli sulle modifiche e la guida all'implementazione per le modifiche di CameraServer, fare riferimento a Camera Framework Hardening .

ExtractorService cambia

Il servizio Extractor ospita gli Extractor , componenti che analizzano i vari formati di file supportati dal media framework. Il servizio di estrazione è il meno privilegiato di tutti i servizi: non può leggere FD, quindi effettua chiamate su un'interfaccia Binder (fornita dal mediaserver for ogni sessione di riproduzione) per accedere ai file.

Un'applicazione (o mediaserver ) effettua una chiamata al processo di estrazione per ottenere un IMediaExtractor , chiama IMediaExtractor per ottenere IMediaSources per la traccia contenuta nel file e quindi chiama IMediaSources per leggere i dati da essi.

Per trasferire i dati tra processi, l'applicazione (o mediaserver ) include i dati nel pacco di risposta come parte della transazione Binder o utilizza la memoria condivisa:

  • L'uso della memoria condivisa richiede una chiamata Binder aggiuntiva per rilasciare la memoria condivisa, ma è più veloce e utilizza meno energia per buffer di grandi dimensioni.
  • L'utilizzo di In-Parcel richiede una copia aggiuntiva, ma è più veloce e utilizza meno energia per buffer inferiori a 64 KB.

Implementazione

Per supportare lo spostamento dei componenti MediaDrm e MediaCrypto nel nuovo processo mediadrmserver , i fornitori devono modificare il metodo di allocazione per i buffer protetti per consentire la condivisione dei buffer tra i processi.

Nelle versioni precedenti di Android, i buffer protetti sono allocati in mediaserver da OMX::allocateBuffer e utilizzati durante la decrittazione nello stesso processo, come mostrato di seguito:

Figura 2. Android 6.0 e allocazione del buffer inferiore in mediaserver.

In Android 7.0, il processo di allocazione del buffer è stato modificato in un nuovo meccanismo che offre flessibilità riducendo al minimo l'impatto sulle implementazioni esistenti. Con gli stack MediaDrm e MediaCrypto nel nuovo processo mediadrmserver , i buffer vengono allocati in modo diverso e i fornitori devono aggiornare gli handle del buffer sicuro in modo che possano essere trasportati attraverso il raccoglitore quando MediaCodec richiama un'operazione di decrittografia su MediaCrypto .

Figura 3. Allocazione del buffer per Android 7.0 e versioni successive in mediaserver.

Utilizzo di handle nativi

OMX::allocateBuffer deve restituire un puntatore a una struttura native_handle , che contiene descrittori di file (FD) e dati interi aggiuntivi. Un native_handle offre tutti i vantaggi dell'utilizzo di FD, incluso il supporto del raccoglitore esistente per la serializzazione/deserializzazione, consentendo al contempo una maggiore flessibilità per i fornitori che attualmente non utilizzano FD.

Utilizzare native_handle_create() per allocare l'handle nativo. Il codice Framework assume la proprietà della struct native_handle allocata ed è responsabile del rilascio delle risorse sia nel processo in cui il native_handle è originariamente allocato sia nel processo in cui viene deserializzato. Il framework rilascia handle nativi con native_handle_close() seguiti da native_handle_delete() e serializza/deserializza native_handle usando Parcel::writeNativeHandle()/readNativeHandle() .

I fornitori di SoC che utilizzano FD per rappresentare buffer sicuri possono popolare l'FD nel native_handle con il proprio FD. I fornitori che non utilizzano FD possono rappresentare buffer sicuri utilizzando campi aggiuntivi in native_buffer .

Impostazione della posizione di decrittazione

I fornitori devono aggiornare il metodo di decrittazione OEMCrypto che opera su native_handle per eseguire tutte le operazioni specifiche del fornitore necessarie per rendere native_handle utilizzabile nel nuovo spazio di processo (le modifiche in genere includono aggiornamenti alle librerie OEMCrypto).

Poiché allocateBuffer è un'operazione OMX standard, Android 7.0 include una nuova estensione OMX ( OMX.google.android.index.allocateNativeHandle ) per eseguire query per questo supporto e una chiamata OMX_SetParameter che notifica all'implementazione OMX che dovrebbe usare handle nativi.