Rafforzamento del framework media

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:

hardening del mediaserver

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:

  1. 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
  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'mediaserver estrazione al processo.
  3. Esegue chiamate Binder IPC all'estrattore per determinare il tipo di dati nel file (ad es. dati MP3 o H.264).
  4. Esegue chiamate al processo mediacodec per creare codec del tipo richiesto; riceve interfacce Binder per questi codec.
  5. 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.