microdroide

Microdroid es un sistema operativo mini-Android que se ejecuta en un pVM. No es necesario utilizar Microdroid, puede iniciar una máquina virtual con cualquier sistema operativo. Sin embargo, los principales casos de uso de 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 ofrecer Android.

Con los sistemas operativos tradicionales, brindar 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 necesitan implementar un medio para cargar y ejecutar de forma segura parte de su aplicación en pVM, y la carga útil se construye contra glibc. La aplicación de Android utiliza Bionic, la comunicación requiere un protocolo personalizado a través de 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 un pVM. El código nativo está construido contra Bionic, la comunicación se realiza a través de Binder, permite importar APEX desde Android y expone un subconjunto de la API de Android, como un 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 de pVM. Soportes para microdroides:

  • Un subconjunto de API de NDK (se proporcionan todas las API para la implementación de libc y Bionic en Android)
  • Funciones de depuración, como adb, logcat, tombstone y gdb
  • Arranque verificado y SELinux habilitados
  • Cargando y ejecutando un binario, junto con bibliotecas compartidas, incrustado en un APK
  • Binder RPC sobre vsock e intercambio de archivos con comprobaciones de integridad implícitas
  • Carga de APEX

Microdroid no soporta:

  • API de Android Java en los paquetes android.\*

  • SystemServer y Zygote

  • Gráficos/UI

  • HAL

Arquitectura de microdroides

Microdroid es similar a Cuttlefish en que ambos tienen una arquitectura similar a la del 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 kernel y el disco ram de inicio.
  • vendor_boot.img : contiene módulos del 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 compuesto 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 ocurre después del inicio del dispositivo . El arranque del dispositivo se analiza en el documento de Arquitectura . La Figura 1 muestra los pasos que se llevan a cabo durante la secuencia de inicio de Microdroid:

Flujo de arranque seguro de la instancia de microdroid

Figura 1. Flujo de arranque seguro de la instancia de microdroid

A continuación te explicamos los pasos:

  1. Crossvm carga el gestor 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 comprobar si proviene de una fuente confiable (Google o un OEM).
    • Garantiza que el mismo gestor de arranque se utilice de forma coherente en varios arranques del mismo pVM mediante el uso de la imagen de instancia. Específicamente, el 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. Entonces, la próxima vez que se inicie pVM con la misma imagen de instancia, pvmfw descifra la identidad guardada de la imagen de instancia y verifica que sea la misma que se guardó anteriormente. Si las identidades difieren, pvmfw se niega a arrancar.

    Luego, el gestor de arranque inicia Microdroid.

  2. El gestor de arranque accede al disco de la instancia. De manera 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.

  3. El gestor de arranque verifica vbmeta y las particiones encadenadas, como boot y super , y, si tiene éxito, deriva los secretos de pVM de la siguiente etapa. Luego, Microdroid entrega el control al kernel.

  4. Debido a que el gestor de arranque ya ha verificado la superpartición (paso 3), el kernel monta incondicionalmente la superpartición. Al igual que con Android completo, la superpartició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 script init.rc es similar al de Android completo pero adaptado a las necesidades de Microdroid.

  5. El proceso init inicia el administrador de Microdroid, que accede a la imagen de la instancia. El servicio de administrador de Microdroid descifra la imagen utilizando la clave pasada en 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. Esta información la utilizan posteriormente zipfuse y apexd cuando montan el APK del cliente y los APEX solicitados, respectivamente.

  6. El servicio de administrador de Microdroid se inicia apexd .

  7. 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 ).

  8. 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 ha solicitado para esta instancia de pVM. apexd utiliza la lista al activar APEX.

  9. El flujo de inicio regresa al servicio del administrador de Microdroid. Luego, el servicio de administrador se comunica con VirtualizationService de Android mediante Binder RPC para que pueda informar eventos importantes como fallas o apagados, y aceptar solicitudes como la finalización del 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 utilicen archivos para entrada, salida y 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 intercambiar 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 controles 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 un 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á destinado a entrada (solo lectura) o salida (lectura-escritura). Para la entrada, la interfaz exige que el contenido coincida 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 del contenido observado 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 cuentan 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 producidas de manera verificable por el pVM.

Carpeta RPC

La mayoría de las interfaces de Android se expresan en AIDL , que está construido sobre el controlador del kernel 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 a través de sockets permite utilizar las interfaces AIDL existentes de Android 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.