Microdroide

Microdroid è un sistema operativo mini-Android che funziona in un pVM. Non è necessario utilizzare Microdroid, puoi avviare una VM con qualsiasi sistema operativo. Tuttavia, i casi d'uso principali per le pVM non sono l'esecuzione di un sistema operativo autonomo, ma piuttosto l'offerta di un ambiente di esecuzione isolato per l'esecuzione di una parte di un'app con garanzie di riservatezza e integrità più elevate di quelle che Android può fornire.

Con i sistemi operativi tradizionali, garantire riservatezza e integrità elevate richiede una discreta quantità di lavoro (spesso duplicato) perché i sistemi operativi tradizionali non si adattano all'architettura generale Android. Ad esempio, con l'architettura Android standard, gli sviluppatori devono implementare un mezzo per caricare ed eseguire in modo sicuro parte della loro app in pVM e il payload è costruito contro glibc. L'app Android utilizza Bionic, la comunicazione richiede un protocollo personalizzato su vsock e il debug utilizzando adb è impegnativo.

Microdroid colma queste lacune fornendo un'immagine del sistema operativo standard progettata per richiedere il minimo sforzo da parte degli sviluppatori per scaricare una parte della loro app in una pVM. Il codice nativo è costruito su Bionic, la comunicazione avviene tramite Binder e consente di importare APEX da Android ed espone un sottoinsieme dell'API Android, come il keystore per operazioni crittografiche con chiavi supportate da hardware. Nel complesso, gli sviluppatori dovrebbero trovare in Microdroid un ambiente familiare con gli strumenti a cui sono abituati nell'intero sistema operativo Android.

Caratteristiche

Microdroid è una versione ridotta di Android con alcuni componenti aggiuntivi specifici per pVM. Microdroid supporta:

  • Un sottoinsieme di API NDK (vengono fornite tutte le API per l'implementazione di libc e Bionic su Android)
  • Funzionalità di debug, come adb, logcat, tombstone e gdb
  • Avvio verificato e SELinux abilitati
  • Caricamento ed esecuzione di un file binario, insieme alle librerie condivise, incorporato in un APK
  • Raccoglitore RPC su vsock e scambio di file con controlli di integrità impliciti
  • Caricamento degli APEX

Microdroid non supporta:

  • API Java Android nei pacchetti android.\*

  • SystemServer e Zigote

  • Grafica/interfaccia utente

  • HAL

Architettura microdroide

Microdroid è simile a Cuttlefish in quanto entrambi hanno un'architettura simile ad Android standard. Microdroid è costituito dalle seguenti immagini di partizioni raggruppate insieme in un'immagine disco composita:

  • bootloader : verifica e avvia il kernel.
  • boot.img - Contiene il kernel e il ramdisk di inizializzazione.
  • vendor_boot.img - Contiene moduli del kernel specifici della VM, come virtio.
  • super.img : è costituito da partizioni logiche di sistema e fornitore.
  • vbmeta.img : contiene metadati di avvio verificati.

Le immagini della partizione vengono fornite in Virtualization APEX e vengono inserite in un'immagine disco composita da VirtualizationService . Oltre all'immagine del disco composito del sistema operativo principale, VirtualizationService è responsabile della creazione di queste altre partizioni:

  • payload : un insieme di partizioni supportate da APEX e APK di Android
  • instance : una partizione crittografata per rendere persistenti i dati di avvio verificati per istanza, come salt per istanza, chiavi pubbliche APEX attendibili e contatori di rollback

Sequenza di avvio

La sequenza di avvio di Microdroid avviene dopo l'avvio del dispositivo . L'avvio del dispositivo è discusso nel documento Architettura . La Figura 1 mostra i passaggi che si svolgono durante la sequenza di avvio di Microdroid:

Flusso di avvio sicuro dell'istanza microdroid

Figura 1. Flusso di avvio sicuro dell'istanza microdroid

Ecco una spiegazione dei passaggi:

  1. Il bootloader viene caricato in memoria da crosvm e pvmfw inizia l'esecuzione. Prima di passare al bootloader, pvmfw esegue due attività:

    • Verifica il bootloader per verificare se proviene da una fonte attendibile (Google o un OEM).
    • Garantisce che lo stesso bootloader venga utilizzato in modo coerente su più avvii della stessa pVM tramite l'uso dell'immagine dell'istanza. Nello specifico, la pVM viene inizialmente avviata con un'immagine di istanza vuota. pvmfw memorizza l'identità del bootloader nell'immagine dell'istanza e la crittografa. Pertanto, la prossima volta che pVM viene avviato con la stessa immagine dell'istanza, pvmfw decodifica l'identità salvata dall'immagine dell'istanza e verifica che sia la stessa salvata in precedenza. Se le identità differiscono, pvmfw si rifiuta di avviarsi.

    Il bootloader avvia quindi Microdroid.

  2. Il bootloader accede al disco dell'istanza. Similmente a pvmfw, il bootloader dispone di un'unità disco dell'istanza con informazioni sulle immagini delle partizioni utilizzate in questa istanza durante gli avviamenti precedenti, inclusa la chiave pubblica.

  3. Il bootloader verifica vbmeta e le partizioni concatenate, come boot e super e, in caso di successo, deriva i segreti pVM della fase successiva. Quindi, Microdroid trasferisce il controllo al kernel.

  4. Poiché la super partizione è già stata verificata dal bootloader (passaggio 3), il kernel monta incondizionatamente la super partizione. Come con l'Android completo, la super partizione è composta da più partizioni logiche montate su dm-verity. Il controllo viene quindi passato al processo init , che avvia vari servizi nativi. Lo script init.rc è simile a quello dell'Android completo ma adattato alle esigenze di Microdroid.

  5. Il processo init avvia il gestore Microdroid, che accede all'immagine dell'istanza. Il servizio di gestione Microdroid decrittografa l'immagine utilizzando la chiave passata dalla fase precedente e legge le chiavi pubbliche e i contatori di rollback dell'APK e degli APEX del client di cui questa pVM si fida. Queste informazioni vengono utilizzate successivamente da zipfuse e apexd quando montano rispettivamente l'APK del client e gli APEX richiesti.

  6. Il servizio di gestione Microdroid avvia apexd .

  7. apexd monta gli APEX nelle directory /apex/<name> . L'unica differenza tra il modo in cui Android e Microdroid montano gli APEX è che in Microdroid i file APEX provengono da dispositivi a blocchi virtuali ( /dev/vdc1 , ...), non da file normali ( /system/apex/*.apex ).

  8. zipfuse è il file system FUSE di Microdroid. zipfuse monta l'APK del client, che è essenzialmente un file Zip come file system. Di seguito, il file APK viene passato come dispositivo a blocchi virtuale dal pVM con dm-verity, come APEX. L'APK contiene un file di configurazione con un elenco di APEX richiesti dallo sviluppatore dell'app per questa istanza pVM. L'elenco viene utilizzato da apexd durante l'attivazione degli APEX.

  9. Il flusso di avvio ritorna al servizio di gestione Microdroid. Il servizio di gestione comunica quindi con VirtualizationService di Android utilizzando Binder RPC in modo che possa segnalare eventi importanti come arresti anomali o arresti anomali e accettare richieste come la chiusura di pVM. Il servizio di gestione legge la posizione del file binario principale dal file di configurazione dell'APK e lo esegue.

Scambio file (AuthFS)

È normale che i componenti Android utilizzino file per input, output e stato e li passino come descrittori di file (tipo ParcelFileDescriptor in AIDL) con accesso controllato dal kernel Android. AuthFS facilita funzionalità simili per lo scambio di file tra endpoint che diffidano reciprocamente oltre i confini della pVM.

Fondamentalmente, AuthFS è un file system remoto con controlli di integrità trasparenti sulle singole operazioni di accesso, simili a fs-verity . I controlli consentono al frontend, ad esempio un programma di lettura di file in esecuzione in una pVM, di rilevare se il backend non attendibile, in genere Android, ha manomesso il contenuto del file.

Per scambiare file, il backend ( fd\_server ) viene avviato con la configurazione per file specificando se è destinato all'input (sola lettura) o all'output (lettura-scrittura). Per l'input, il frontend impone che i contenuti corrispondano a un hash noto, in cima a un albero Merkle per la verifica all'accesso. Per l'output, AuthFS mantiene internamente un albero hash dei contenuti osservato dalle operazioni di scrittura e può garantire l'integrità quando i dati vengono riletti.

Il trasporto sottostante è attualmente basato su Binder RPC, tuttavia ciò potrebbe cambiare in futuro per ottimizzare le prestazioni.

Gestione delle chiavi

Le pVM sono dotate di una chiave di sigillatura stabile adatta a dati persistenti protetti e di una chiave di attestazione adatta a produrre firme prodotte in modo verificabile dalla pVM.

Raccoglitore RPC

La maggior parte delle interfacce di Android sono espresse in AIDL , che è costruito sul driver del kernel Binder Linux. Per supportare le interfacce tra pVM, il protocollo Binder è stato riscritto per funzionare su socket, vsock nel caso di pVM. Il funzionamento tramite socket consente di utilizzare le interfacce AIDL esistenti di Android in questo nuovo ambiente.

Per impostare la connessione, un endpoint, come il payload pVM, crea un oggetto RpcServer , registra un oggetto root e inizia ad ascoltare nuove connessioni. I client possono connettersi a questo server utilizzando un oggetto RpcSession , ottenere l'oggetto Binder e utilizzarlo esattamente come viene utilizzato un oggetto Binder con il driver Binder del kernel.