Per migliorare la sicurezza del dispositivo, Android 7.0 suddivide il processo monoliticomediaserver
in più processi con autorizzazioni e funzionalità limitate solo a quelle richieste da ciascun processo. Queste modifiche attenuano le vulnerabilità di sicurezza del framework multimediale in quanto:
- Suddivisione dei componenti della pipeline AV in processi in sandbox specifici per l'app.
- Attivazione di componenti multimediali aggiornabili (estrattori, codec e così via).
Queste modifiche migliorano anche la sicurezza per gli utenti finali riducendo notevolmente la gravità della maggior parte delle vulnerabilità di sicurezza relative ai contenuti multimediali, proteggendo i dispositivi e i dati degli utenti finali.
Gli OEM e i fornitori di SoC devono aggiornare le modifiche all'HAL e al framework per renderli compatibili con la nuova architettura. Nello specifico, poiché il codice Android fornito dal fornitore spesso presuppone che tutto venga eseguito nella stessa procedura, i fornitori devono aggiornare il proprio codice per trasmettere handle nativi (native_handle
) che abbiano un significato in più procedure. Per un'implementazione di riferimento delle modifiche
relative al rafforzamento dei contenuti multimediali, consulta frameworks/av
e
frameworks/native
.
Modifiche all'architettura
Le versioni precedenti di Android utilizzavano un singolo processo monoliticomediaserver
con molte autorizzazioni (accesso alla fotocamera, accesso all'audio, accesso al driver video, accesso ai file, accesso alla rete e così via). Android
7.0 suddivide il processo mediaserver
in diversi nuovi processi che
ognuno richiede un insieme molto più piccolo di autorizzazioni:
Figura 1. Modifiche all'architettura per la protezione avanzata del media server
Questa nuova architettura garantisce che, anche se un processo viene compromesso, il codice dannoso non abbia accesso all'intero insieme di autorizzazioni precedentemente detenuto da mediaserver
. I processi sono limitati dai criteri SELinux e seccomp.
Nota: a causa delle dipendenze dal fornitore, alcuni codec vengono ancora eseguiti in mediaserver
e di conseguenza concedono a mediaserver
più autorizzazioni del necessario. Nello specifico, Widevine Classic continua a funzionare in mediaserver
per Android 7.0.
Modifiche a MediaServer
In Android 7.0 esiste il processo mediaserver
per gestire la riproduzione e la registrazione, ad esempio il passaggio e la sincronizzazione dei buffer tra componenti e processi. I processi comunicano tramite il meccanismo Binder
standard.
In una sessione di riproduzione di file locale standard, l'app passa un descrittore di file (FD) a mediaserver
(di solito tramite l'API Java MediaPlayer) e mediaserver
:
- Avvolge l'FD in un oggetto DataSource di Binder che viene passato al processo di estrazione, che lo utilizza per leggere dal file utilizzando Binder IPC. MediaExtractor non riceve l'FD, ma richiama Binder per recuperare i dati.
mediaserver
- Esamina il file, crea l'estrattore appropriato per il tipo di file
(ad es. MP3Extractor o MPEG4Extractor) e restituisce un'interfaccia Binder per l'
mediaserver
estrazione al processo. - Esegue chiamate Binder IPC all'estrattore per determinare il tipo di dati nel file (ad es. dati MP3 o H.264).
- Esegue chiamate al processo
mediacodec
per creare codec del tipo richiesto; riceve interfacce Binder per questi codec. - Esegue chiamate IPC Binder ripetute all'estrattore per leggere i campioni codificati, utilizza l'IPC Binder per inviare i dati codificati al processo
mediacodec
per la decodifica e riceve i dati decodificati.
In alcuni casi d'uso, non è coinvolto alcun codec (ad esempio una riproduzione di contenuti offloaded in cui i dati codificati vengono inviati direttamente al dispositivo di output) oppure il codec può eseguire il rendering dei dati decodificati direttamente anziché restituire un buffer di dati decodificati (riproduzione di video).
Modifiche a MediaCodecService
Il servizio codec è il luogo in cui si trovano gli encoder e i decoder. A causa delle dipendenze dei fornitori, non tutti i codec sono ancora disponibili nel processo. In Android 7.0:
- I decodificatori e i codificatori software non sicuri si trovano nel processo del codec.
- I decodificatori e i codificatori hardware sicuri si trovano nella sezione
mediaserver
(invariato).
Un'app (o mediaserver
) chiama il processo del codec per creare un codec del tipo richiesto, quindi chiama il codec per passare i dati codificati e recuperare i dati decodificati (per la decodifica) o per passare i dati decodificati e recuperare i dati codificati (per la codifica). Il trasferimento dei dati da e verso i codec utilizza già la memoria condivisa, pertanto questo processo rimane invariato.
Modifiche a MediaDrmServer
Il server DRM viene utilizzato per riprodurre contenuti protetti da DRM, ad esempio i film su Google Play Film. Gestisce la decrittografia dei dati criptati in modo sicuro, e di conseguenza ha accesso all'archiviazione di certificati e chiavi e ad altri componenti sensibili. A causa delle dipendenze dai fornitori, la procedura DRM non viene ancora utilizzata in tutti i casi.
Modifiche ad AudioServer
Il processo AudioServer ospita componenti relativi all'audio, come l'input e l'output audio, il servizio policymanager che determina l'instradamento dell'audio e il servizio radio FM. Per informazioni dettagliate sulle modifiche all'audio e sulle indicazioni per l'implementazione, consulta Implementare l'audio.
Modifiche a CameraServer
CameraServer controlla la videocamera e viene utilizzato durante la registrazione video per ottenere i frame video dalla videocamera e poi trasmetterli a mediaserver
per un'ulteriore elaborazione. Per informazioni dettagliate sulle modifiche e sulle linee guida per l'implementazione delle modifiche di CameraServer, consulta la sezione Ottimizzazione della sicurezza del framework della videocamera.
Modifiche a ExtractorService
Il servizio di estrazione ospita gli estrattori, componenti che analizzano i vari formati file supportati dal framework multimediale. Il servizio di estrazione
è quello con meno privilegi di tutti i servizi: non può leggere i file di indirizzo, quindi
effettua chiamate a un'interfaccia Binder (fornita dall'mediaserver for
di ogni sessione di riproduzione) per accedere ai file.
Un'app (o mediaserver
) effettua una chiamata al processo di estrazione per ottenere un IMediaExtractor
, chiama questo IMediaExtractor
per ottenere IMediaSources
per la traccia contenuta nel file e poi chiama IMediaSources
per leggere i dati.
Per trasferire i dati tra i processi, l'app (o
mediaserver
) include i dati nel reply-Parcel nell'ambito della
transazione Binder o utilizza la memoria condivisa:
- L'utilizzo della memoria condivisa richiede una chiamata Binder aggiuntiva per liberare la memoria condivisa, ma è più veloce e consuma meno energia per buffer di grandi dimensioni.
- L'utilizzo di in-Parcel richiede copie aggiuntive, ma è più veloce e richiede meno energia per i buffer più piccoli di 64 KB.
Implementazione
Per supportare il trasferimento dei componenti MediaDrm
e MediaCrypto
nel nuovo processo mediadrmserver
, i fornitori devono modificare
il metodo di allocazione dei buffer sicuri per consentire la condivisione dei buffer tra
processi.
Nelle release precedenti di Android, gli spazi buffer sicuri vengono allocati in mediaserver
da OMX::allocateBuffer
e utilizzati durante la decrittografia nella stessa procedura, come mostrato di seguito:
Figura 2. Allokazione del buffer in mediaserver per Android 6.0 e versioni precedenti.
In Android 7.0, la procedura di allocazione del buffer è passata a 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 i handle dei buffer sicuri in modo che possano essere
trasportati tramite il binder quando MediaCodec
invoca un'operazione di decrittografia su MediaCrypto
.
Figura 3. Android 7.0 e versioni successive allocazione buffer in mediaserver.
Utilizza gli handle nativi
OMX::allocateBuffer
deve restituire un puntatore a una struttura native_handle
, che contiene descrittori file (FD) e dati interi aggiuntivi. Un native_handle
offre tutti i vantaggi dell'utilizzo dei dati federati, incluso il supporto esistente dei binder per la serializzazione/deserializzazione, consentendo al contempo una maggiore flessibilità per i fornitori che al momento non li utilizzano.
Utilizza native_handle_create()
per allocare l'handle nativo.
Il codice del framework acquisisce la proprietà della struttura native_handle
allocata ed è responsabile del rilascio delle risorse sia nel processo in cui
native_handle
viene allocata originariamente sia nel processo in cui
viene deserializzata. Il framework rilascia handle nativi con
native_handle_close()
seguito da
native_handle_delete()
e esegue la serializzazione/deserializzazione del
native_handle
utilizzando
Parcel::writeNativeHandle()/readNativeHandle()
.
I fornitori di SoC che utilizzano gli FD per rappresentare i buffer sicuri possono compilare l'FD in
native_handle
con il proprio FD. I fornitori che non utilizzano gli FD possono rappresentare i buffer sicuri utilizzando campi aggiuntivi nel native_buffer
.
Impostare la posizione di decrittografia
I fornitori devono aggiornare il metodo di decrittografia OEMCrypto che opera su native_handle
per eseguire le operazioni specifiche del fornitore necessarie per rendere native_handle
utilizzabile nel nuovo spazio dei processi (le modifiche tipicamente 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 su questo supporto e una chiamata OMX_SetParameter
che comunica all'implementazione OMX che deve utilizzare handle nativi.