Microdroid es un sistema operativo mini-Android que se ejecuta en una pVM. No tiene que usar Microdroid, puede iniciar una máquina virtual con cualquier sistema operativo. Sin embargo, los principales casos de uso de las pVM no son ejecutar un sistema operativo independiente, sino ofrecer un entorno de ejecución aislado para ejecutar una parte de una aplicación con garantías de confidencialidad e integridad más sólidas que las que puede brindar Android.
Con los sistemas operativos tradicionales, proporcionar una sólida confidencialidad e integridad requiere una gran cantidad de trabajo (a menudo duplicado) porque los sistemas operativos tradicionales no encajan con la arquitectura general de Android. Por ejemplo, con la arquitectura estándar de Android, los desarrolladores deben implementar un medio para cargar y ejecutar de forma segura parte de su aplicación en la pVM, y la carga útil se crea con glibc. La aplicación de Android usa Bionic, la comunicación requiere un protocolo personalizado sobre vsock y la depuración con adb es un desafío.
Microdroid llena estos vacíos al proporcionar una imagen de sistema operativo lista para usar diseñada para requerir la menor cantidad de esfuerzo por parte de los desarrolladores para descargar una parte de su aplicación en una pVM. El código nativo se basa en Bionic, la comunicación se realiza a través de Binder y permite importar APEX desde Android y expone un subconjunto de la API de Android, como el almacén de claves para operaciones criptográficas con claves respaldadas por hardware. En general, los desarrolladores deberían encontrar en Microdroid un entorno familiar con las herramientas a las que se han acostumbrado en el sistema operativo Android completo.
Características
Microdroid es una versión simplificada de Android con algunos componentes adicionales específicos para pVM. Microdroid admite:
- Un subconjunto de API de NDK (se proporcionan todas las API para la implementación de Android de libc y Bionic)
- Funciones de depuración, como adb, logcat, tombstone y gdb
- Arranque verificado y SELinux habilitado
- Cargar y ejecutar un binario, junto con bibliotecas compartidas, integrado en un APK
- Binder RPC sobre vsock e intercambio de archivos con controles de integridad implícitos
- Carga de APEX
Microdroid no admite:
API Java de Android en los paquetes
android.\*
SystemServer y Zygote
Gráficos/IU
HAL
Arquitectura de microdroide
Microdroid es similar a Cuttlefish en que ambos tienen una arquitectura similar a la de Android estándar. Microdroid consta de las siguientes imágenes de partición agrupadas en una imagen de disco compuesta:
-
bootloader
- Verifica e inicia el kernel. -
boot.img
- Contiene el núcleo y el ramdisk de inicio. -
vendor\_boot.img
: contiene módulos de kernel específicos de VM, como virtio. -
super.img
: consta de particiones lógicas del sistema y del proveedor. -
vbmeta.img
: contiene metadatos de arranque verificados.
Las imágenes de partición se envían en Virtualization APEX y VirtualizationService
las empaqueta en una imagen de disco compuesta. Además de la imagen de disco compuesta del sistema operativo principal, VirtualizationService
es responsable de crear estas otras particiones:
-
payload
: un conjunto de particiones respaldadas por APEX y APK de Android -
instance
: una partición cifrada para conservar datos de arranque verificados por instancia, como sal por instancia, claves públicas APEX confiables y contadores de reversión
Secuencia de inicio
La secuencia de inicio de Microdroid se produce después del inicio del dispositivo . El arranque del dispositivo se analiza en el documento Arquitectura . La Figura 1 muestra los pasos que tienen lugar durante la secuencia de arranque de Microdroid:
Aquí hay una explicación de los pasos:
crossvm carga el cargador de arranque en la memoria y pvmfw comienza a ejecutarse. Antes de saltar al gestor de arranque, pvmfw realiza dos tareas:
- Verifica el gestor de arranque para verificar si es de una fuente confiable (Google o un OEM).
- Garantiza que el mismo gestor de arranque se utilice de forma coherente en varios arranques de la misma pVM mediante el uso de la imagen de la instancia. Específicamente, la pVM se inicia inicialmente con una imagen de instancia vacía. pvmfw almacena la identidad del gestor de arranque en la imagen de la instancia y la cifra. Por lo tanto, la próxima vez que se inicie pVM con la misma imagen de instancia, pvmfw descifrará la identidad guardada de la imagen de instancia y verificará que sea la misma que se guardó anteriormente. Si las identidades difieren, pvmfw se niega a arrancar.
El gestor de arranque luego inicia Microdroid.
El gestor de arranque accede al disco de la instancia. Similar a pvmfw, el gestor de arranque tiene una unidad de disco de instancia con información sobre las imágenes de partición utilizadas en esta instancia durante arranques anteriores, incluida la clave pública.
El cargador de arranque verifica vbmeta y las particiones encadenadas, como
boot
ysuper
, y, si tiene éxito, deriva los secretos de pVM de la siguiente etapa. Luego, Microdroid entrega el control al kernel.Debido a que el cargador de arranque ya ha verificado la superpartición (paso 3), el núcleo monta incondicionalmente la superpartición. Al igual que con el Android completo, la súper partición consta de múltiples particiones lógicas montadas sobre dm-verity. Luego, el control se pasa al proceso
init
, que inicia varios servicios nativos. El scriptinit.rc
es similar al de Android completo pero adaptado a las necesidades de Microdroid.El proceso
init
inicia el administrador de Microdroid, que accede a la imagen de la instancia. El servicio del administrador de Microdroid descifra la imagen utilizando la clave pasada de la etapa anterior y lee las claves públicas y los contadores de reversión del APK del cliente y los APEX en los que confía este pVM.zipfuse
yapexd
utilizan esta información más tarde cuando montan el APK del cliente y los APEX solicitados, respectivamente.El servicio del administrador de Microdroid inicia
apexd
.apexd
monta los APEX en los directorios/apex/<name>
. La única diferencia entre cómo Android y Microdroid montan APEX es que en Microdroid, los archivos APEX provienen de dispositivos de bloques virtuales (/dev/vdc1
, …), no de archivos normales (/system/apex/*.apex
).zipfuse
es el sistema de archivos FUSE de Microdroid.zipfuse
monta el APK del cliente, que es esencialmente un archivo Zip como sistema de archivos. Debajo, el pVM pasa el archivo APK como un dispositivo de bloque virtual con dm-verity, al igual que APEX. El APK contiene un archivo de configuración con una lista de APEX que el desarrollador de la aplicación solicitó para esta instancia de pVM. La lista es utilizada porapexd
al activar APEX.El flujo de arranque vuelve al servicio de administrador de Microdroid. Luego, el servicio del administrador se comunica con
VirtualizationService
de Android mediante Binder RPC para que pueda informar eventos importantes, como bloqueos o apagados, y aceptar solicitudes, como la terminación de la pVM. El servicio de administrador lee la ubicación del binario principal del archivo de configuración del APK y lo ejecuta.
Intercambio de archivos (AuthFS)
Es común que los componentes de Android usen archivos para la entrada, la salida y el estado y los pasen como descriptores de archivos (tipo ParcelFileDescriptor
en AIDL) con acceso controlado por el kernel de Android. AuthFS facilita una funcionalidad similar para el intercambio de archivos entre puntos finales que desconfían mutuamente a través de los límites de pVM.
Fundamentalmente, AuthFS es un sistema de archivos remoto con verificaciones de integridad transparentes en operaciones de acceso individuales, similar a fs-verity
. Las comprobaciones permiten que el frontend, como un programa de lectura de archivos que se ejecuta en una pVM, detecte si el backend que no es de confianza, normalmente Android, manipuló el contenido del archivo.
Para intercambiar archivos, el backend ( fd\_server
) se inicia con una configuración por archivo que especifica si está diseñado para entrada (solo lectura) o salida (lectura-escritura). Para la entrada, la interfaz exige que los contenidos coincidan con un hash conocido, en la parte superior de un árbol Merkle para la verificación en el acceso. Para la salida, AuthFS mantiene internamente un árbol hash de los contenidos observados en las operaciones de escritura y puede imponer la integridad cuando se vuelven a leer los datos.
El transporte subyacente se basa actualmente en Binder RPC, sin embargo, eso podría cambiar en el futuro para optimizar el rendimiento.
Gestión de claves
Los pVM se proporcionan con una clave de sellado estable que es adecuada para datos persistentes protegidos y una clave de atestación que es adecuada para producir firmas que el pVM produce de manera verificable.
Aglutinante RPC
La mayoría de las interfaces de Android se expresan en AIDL , que se basa en el controlador del kernel de Binder Linux. Para admitir interfaces entre pVM, el protocolo Binder se ha reescrito para que funcione sobre sockets, vsock en el caso de pVM. Operar sobre sockets permite que las interfaces AIDL existentes de Android se utilicen en este nuevo entorno.
Para configurar la conexión, un punto final, como la carga útil de pVM, crea un objeto RpcServer
, registra un objeto raíz y comienza a escuchar nuevas conexiones. Los clientes pueden conectarse a este servidor usando un objeto RpcSession
, obtener el objeto Binder
y usarlo exactamente como se usa un objeto Binder
con el controlador Binder del kernel.