Endurecimiento del marco de medios

Para mejorar la seguridad del dispositivo, Android 7.0 divide el proceso monolítico del mediaserver de medios en múltiples procesos con permisos y capacidades restringidas solo a las requeridas por cada proceso. Estos cambios mitigan las vulnerabilidades de seguridad del marco de medios al:

  • Dividir los componentes de canalización AV en procesos de espacio aislado específicos de la aplicación.
  • Habilitación de componentes multimedia actualizables (extractores, códecs, etc.).

Estos cambios también mejoran la seguridad de los usuarios finales al reducir significativamente la gravedad de la mayoría de las vulnerabilidades de seguridad relacionadas con los medios, manteniendo seguros los dispositivos y los datos de los usuarios finales.

Los fabricantes de equipos originales y los proveedores de SoC deben actualizar su HAL y los cambios de marco para hacerlos compatibles con la nueva arquitectura. Específicamente, debido a que el código de Android proporcionado por el proveedor a menudo asume que todo se ejecuta en el mismo proceso, los proveedores deben actualizar su código para pasar identificadores nativos ( native_handle ) que tienen significado en todos los procesos. Para obtener una implementación de referencia de los cambios relacionados con el refuerzo de medios, consulte frameworks/av y frameworks/native .

Cambios arquitectónicos

Las versiones anteriores de Android usaban un único proceso de mediaserver de medios monolítico con una gran cantidad de permisos (acceso a la cámara, acceso al audio, acceso al controlador de video, acceso a archivos, acceso a la red, etc.). Android 7.0 divide el proceso del mediaserver de medios en varios procesos nuevos, cada uno de los cuales requiere un conjunto de permisos mucho más pequeño:

endurecimiento del servidor de medios

Figura 1. Cambios de arquitectura para el refuerzo del servidor de medios

Esta nueva arquitectura garantiza que, incluso si un proceso se ve comprometido, el código malicioso no tiene acceso al conjunto completo de permisos que antes tenía mediaserver. Los procesos están restringidos por las políticas de SElinux y seccomp.

Nota: debido a las dependencias de los proveedores, algunos códecs aún se ejecutan en el mediaserver de medios y, en consecuencia, otorgan al servidor de mediaserver más permisos de los necesarios. Específicamente, Widevine Classic continúa ejecutándose en el mediaserver de medios para Android 7.0.

Cambios en el servidor de medios

En Android 7.0, el proceso del mediaserver de medios existe para controlar la reproducción y la grabación, por ejemplo, pasar y sincronizar búferes entre componentes y procesos. Los procesos se comunican a través del mecanismo Binder estándar.

En una sesión de reproducción de archivo local estándar, la aplicación pasa un descriptor de archivo (FD) al mediaserver de medios (generalmente a través de la API Java de MediaPlayer) y el mediaserver de medios:

  1. Envuelve el FD en un objeto Binder DataSource que se pasa al proceso de extracción, que lo usa para leer el archivo mediante Binder IPC. (El extractor de medios no obtiene el FD, sino que hace que Binder vuelva a llamar al mediaserver de medios para obtener los datos).
  2. Examina el archivo, crea el extractor adecuado para el tipo de archivo (por ejemplo, MP3Extractor o MPEG4Extractor) y devuelve una interfaz Binder para el extractor al proceso del mediaserver .
  3. Hace llamadas Binder IPC al extractor para determinar el tipo de datos en el archivo (por ejemplo, datos MP3 o H.264).
  4. Llama al proceso de mediacodec para crear códecs del tipo requerido; recibe interfaces Binder para estos códecs.
  5. Realiza repetidas llamadas de Binder IPC al extractor para leer muestras codificadas, utiliza Binder IPC para enviar datos codificados al proceso de mediacodec para su decodificación y recibe datos decodificados.

En algunos casos de uso, no interviene ningún códec (como una reproducción descargada donde los datos codificados se envían directamente al dispositivo de salida), o el códec puede procesar los datos decodificados directamente en lugar de devolver un búfer de datos decodificados (reproducción de video).

Cambios en MediaCodecService

El servicio de códec es donde viven los codificadores y decodificadores. Debido a las dependencias de los proveedores, todavía no todos los códecs viven en el proceso de códecs. En Android 7.0:

  • Los decodificadores y codificadores de software no seguros viven en el proceso de códec.
  • Los decodificadores seguros y los codificadores de hardware viven en el mediaserver de medios (sin cambios).

Una aplicación (o servidor de medios) llama al proceso de códec para crear un códec del tipo requerido, luego llama a ese códec para pasar datos codificados y recuperar datos decodificados (para decodificación) o para pasar datos decodificados y recuperar datos codificados (para codificación) . La transferencia de datos hacia y desde los códecs ya utiliza la memoria compartida, por lo que el proceso no se modifica.

Cambios en MediaDrmServer

El servidor DRM se usa cuando se reproduce contenido protegido por DRM, como películas en Google Play Movies. Maneja el descifrado de los datos cifrados de manera segura y, como tal, tiene acceso al almacenamiento de certificados y claves y otros componentes confidenciales. Debido a las dependencias de los proveedores, el proceso DRM aún no se utiliza en todos los casos.

Cambios en el servidor de audio

El proceso de AudioServer alberga componentes relacionados con el audio, como la entrada y salida de audio, el servicio de administrador de políticas que determina el enrutamiento de audio y el servicio de radio FM. Para obtener detalles sobre los cambios de audio y la guía de implementación, consulte Implementación de audio .

Cambios en CameraServer

CameraServer controla la cámara y se usa al grabar video para obtener fotogramas de video de la cámara y luego pasarlos al mediaserver de medios para su posterior manejo. Para obtener detalles sobre los cambios y la guía de implementación de los cambios de CameraServer, consulte Camera Framework Hardening .

Cambios de ExtractorService

El servicio de extracción aloja los extractores , componentes que analizan los distintos formatos de archivo admitidos por el marco de medios. El servicio de extracción es el menos privilegiado de todos los servicios: no puede leer FD, por lo que realiza llamadas a una interfaz Binder (proporcionada por el mediaserver for cada sesión de reproducción) para acceder a los archivos.

Una aplicación (o mediaserver ) hace una llamada al proceso extractor para obtener un IMediaExtractor , llama a ese IMediaExtractor para obtener IMediaSources para la pista contenida en el archivo y luego llama a IMediaSources para leer datos de ellos.

Para transferir los datos entre procesos, la aplicación (o mediaserver ) incluye los datos en el paquete de respuesta como parte de la transacción de Binder o usa la memoria compartida:

  • El uso de la memoria compartida requiere una llamada de Binder adicional para liberar la memoria compartida, pero es más rápido y usa menos energía para búferes grandes.
  • El uso de In-Parcel requiere una copia adicional, pero es más rápido y usa menos energía para búferes de menos de 64 KB.

Implementación

Para respaldar el movimiento de los componentes MediaDrm y MediaCrypto al nuevo proceso mediadrmserver , los proveedores deben cambiar el método de asignación de búferes seguros para permitir que los búferes se compartan entre procesos.

En versiones anteriores de Android, OMX::allocateBuffer asigna búferes seguros en mediaserver y se usan durante el descifrado en el mismo proceso, como se muestra a continuación:

Figura 2. Android 6.0 y asignación de búfer inferior en mediaserver.

En Android 7.0, el proceso de asignación de búfer cambió a un nuevo mecanismo que brinda flexibilidad y minimiza el impacto en las implementaciones existentes. Con las pilas MediaDrm y MediaCrypto en el nuevo proceso mediadrmserver , los búferes se asignan de manera diferente y los proveedores deben actualizar los identificadores de búfer seguros para que puedan transportarse a través de la carpeta cuando MediaCodec invoca una operación de descifrado en MediaCrypto .

Figura 3. Android 7.0 y asignación de búfer superior en mediaserver.

Uso de identificadores nativos

OMX::allocateBuffer debe devolver un puntero a una estructura native_handle , que contiene descriptores de archivos (FD) y datos enteros adicionales. Un native_handle tiene todas las ventajas de usar FD, incluido el soporte de carpeta existente para serialización/deserialización, al tiempo que permite una mayor flexibilidad para los proveedores que actualmente no usan FD.

Utilice native_handle_create() para asignar el identificador nativo. El código del marco toma posesión de la estructura native_handle asignada y es responsable de liberar recursos tanto en el proceso en el que se asigna originalmente native_handle como en el proceso en el que se deserializa. El marco lanza identificadores nativos con native_handle_close() seguido de native_handle_delete() y serializa/deserializa native_handle usando Parcel::writeNativeHandle()/readNativeHandle() .

Los proveedores de SoC que usan FD para representar búferes seguros pueden completar el FD en native_handle con su FD. Los proveedores que no usan FD pueden representar búferes seguros usando campos adicionales en native_buffer .

Configuración de la ubicación de descifrado

Los proveedores deben actualizar el método de descifrado de OEMCrypto que opera en native_handle para realizar las operaciones específicas del proveedor necesarias para que native_handle pueda utilizar en el nuevo espacio de proceso (los cambios suelen incluir actualizaciones de las bibliotecas de OEMCrypto).

Dado que allocateBuffer es una operación OMX estándar, Android 7.0 incluye una nueva extensión OMX ( OMX.google.android.index.allocateNativeHandle ) para consultar esta compatibilidad y una llamada OMX_SetParameter que notifica a la implementación de OMX que debe usar identificadores nativos.