Extensión de etiquetado de memoria de ARM

Arm v9 presenta Arm Memory La extensión de etiquetado (MTE), una implementación de hardware de memoria etiquetada.

En un nivel alto, MTE etiqueta cada asignación/desasignación de memoria con metadatos adicionales. Asigna una etiqueta a una ubicación de memoria, que luego puede asociados con punteros que hacen referencia a esa ubicación de memoria. En el tiempo de ejecución, la CPU comprueba que el puntero y las etiquetas de metadatos coincidan en cada carga y almacenamiento.

En Android 12, el asignador de memoria del montón del kernel y el espacio del usuario puede aumentar cada asignación con metadatos. Esto ayuda a detectar casos de uso de desbordamiento de búfer, que son la fuente más común de errores de seguridad de la memoria nuestras bases de código.

Modos de operación de MTE

MTE tiene tres modos de funcionamiento:

  • Modo síncrono (SYNC)
  • Modo asíncrono (ASYNC)
  • Modo asimétrico (ASYMM)

Modo síncrono (SYNC)

Este modo está optimizado para la corrección de la detección de errores sobre el rendimiento puede usarse como una herramienta precisa de detección de errores cuando se necesita una sobrecarga de rendimiento más alta aceptable. Cuando MTE SYNC está habilitado, actúa como mitigación de seguridad. Si la etiqueta no coincide, el procesador anula la ejecución inmediatamente y finaliza el proceso con SIGSEGV (código SEGV_MTESERR) y la información completa sobre el acceso a la memoria y el dirección con errores.

Recomendamos usar este modo durante las pruebas como alternativa al HWASan/KASAN o en producción cuando el proceso objetivo representa un superficie de ataque. Además, cuando el modo ASYNC indica la presencia de una puedes obtener un informe de errores preciso usando las APIs de tiempo de ejecución para ejecución en el modo SYNC.

Cuando se ejecuta en modo SYNC, el asignador de Android registra los seguimientos de pila de todos asignaciones y desasignaciones los usa para proporcionar mejores informes de errores que incluyan una explicación de la existencia de como use-after-free o desbordamiento del búfer, y los seguimientos de pila de la los eventos de memoria relevantes. Dichos informes proporcionan más información contextual y y hacen que los errores sean más fáciles de rastrear y corregir.

Modo asíncrono (ASYNC)

Este modo está optimizado para mejorar el rendimiento por sobre la precisión de los informes de errores y puede usarse como detección de baja sobrecarga para errores de seguridad de la memoria.
En una discrepancia de etiqueta, el procesador continúa la ejecución hasta que una entrada de kernel (por ejemplo, una llamada de sistema o una interrupción de temporizador), donde finaliza el proceso con SIGSEGV (código SEGV_MTEAERR) sin para registrar la dirección con errores o el acceso a la memoria.
Recomendamos usar este modo en producción, en bases de código bien probadas, en las que se sabe que la densidad de errores de seguridad de la memoria es baja, lo que se logra usando el modo SYNC durante las pruebas.

Modo asimétrico (ASYMM)

El modo MTE asimétrico, que es una función adicional en Arm v8.7-A, brinda control comprobar lecturas de memoria y verificación asíncrona de escrituras de memoria con un rendimiento similar al del modo ASYNC. En la mayoría de las situaciones, este es una mejora con respecto al modo ASYNC, por lo que recomendamos usarlo en lugar de ASYNC siempre que esté disponible.

Por este motivo, ninguna de las APIs que se describen a continuación menciona el modelo . En cambio, el SO se puede configurar para que siempre use el modo asimétrico cuando Se solicita el modo asíncrono. Consulta la sección "Cómo configurar la CPU nivel de MTE preferido" para obtener más información.

MTE en el espacio del usuario

En las siguientes secciones, se describe cómo se puede habilitar MTE para los procesos del sistema y aplicaciones. MTE está inhabilitada de forma predeterminada, a menos que se cumpla una de las siguientes opciones Se puede configurar para un proceso en particular (consulta a continuación los componentes que MTE está habilitada).

Cómo habilitar MTE con el sistema de compilación

Como propiedad de todo el proceso, la MTE se controla mediante la configuración de tiempo de compilación de el ejecutable principal. Las siguientes opciones permiten cambiar esta configuración para ejecutables individuales o para subdirectorios completos en el árbol de fuentes. El se ignora en las bibliotecas o en cualquier destino que no sea ejecutable ni la prueba.

1. Se habilitó MTE en Android.bp (ejemplo). para un proyecto en particular:

Modo MTE Configuración
MTE asíncrona
  sanitize: {
  memtag_heap: true,
  }
MTE síncrona
  sanitize: {
  memtag_heap: true,
  diag: {
  memtag_heap: true,
  },
  }

o en Android.mk:

Modo MTE Configuración
Asynchronous MTE LOCAL_SANITIZE := memtag_heap
Synchronous MTE LOCAL_SANITIZE := memtag_heap
LOCAL_SANITIZE_DIAG := memtag_heap

2. Habilita MTE en un subdirectorio del árbol de fuentes con un producto variable:

Modo MTE Incluir lista Excluir lista
asincrónico PRODUCT_MEMTAG_HEAP_ASYNC_INCLUDE_PATHS MEMTAG_HEAP_ASYNC_INCLUDE_PATHS PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS MEMTAG_HEAP_EXCLUDE_PATHS
sincronizar PRODUCT_MEMTAG_HEAP_SYNC_INCLUDE_PATHS MEMTAG_HEAP_SYNC_INCLUDE_PATHS

o

Modo MTE Configuración
MTE asíncrona MEMTAG_HEAP_ASYNC_INCLUDE_PATHS
MTE síncrona MEMTAG_HEAP_SYNC_INCLUDE_PATHS

o especificando la ruta de acceso de exclusión de un ejecutable:

Modo MTE Configuración
MTE asíncrona PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS MEMTAG_HEAP_EXCLUDE_PATHS
MTE síncrona

Ejemplo (uso similar a PRODUCT_CFI_INCLUDE_PATHS)

  PRODUCT_MEMTAG_HEAP_SYNC_INCLUDE_PATHS=vendor/$(vendor)
  PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS=vendor/$(vendor)/projectA \
                                    vendor/$(vendor)/projectB

Cómo habilitar MTE con las propiedades del sistema

La configuración de compilación anterior se puede anular en el tiempo de ejecución estableciendo siguiente propiedad del sistema:

arm64.memtag.process.<basename> = (off|sync|async)

En el ejemplo anterior, basename significa el nombre base del ejecutable.

Por ejemplo, para establecer /system/bin/ping o /data/local/tmp/ping. Para usar MTE asíncrona, usa adb shell setprop arm64.memtag.process.ping async.

Habilita MTE con una variable de entorno

Otra forma de anular la configuración de compilación es definir el entorno variable: MEMTAG_OPTIONS=(off|sync|async) Si se definen la variable de entorno y la propiedad del sistema, la variable tiene prioridad.

Cómo habilitar MTE para apps

Si no se especifica, MTE está inhabilitada de forma predeterminada, pero las apps que quieran usar MTE pueden hacerlo configurando android:memtagMode con <application> o <process> en el AndroidManifest.xml

android:memtagMode=(off|default|sync|async)

Cuando se establece en la etiqueta <application>, el afecta a todos los procesos que usa la app y se puede anular para procesos individuales estableciendo el Etiqueta <process>.

Para la experimentación, la compatibilidad cambios se pueden usar para establecer el valor predeterminado de El atributo memtagMode de una app que sí lo hace no especifica ningún valor en el manifiesto (o especifica default).
Puedes encontrarlos en System > Advanced > Developer options > App Compatibility Changes en el menú de configuración global. Parámetro de configuración NATIVE_MEMTAG_ASYNC o NATIVE_MEMTAG_SYNC habilitan MTE de una aplicación en particular.
Como alternativa, esto se puede configurar usando am. comando de la siguiente manera:

$ adb shell am compat enable NATIVE_MEMTAG_[A]SYNC my.app.name

Compila una imagen del sistema de MTE

Recomendamos habilitar MTE en todos los objetos binarios nativos durante el desarrollo y mencionarlo. Esto ayuda a detectar errores de seguridad de la memoria de forma temprana la cobertura de usuarios, si está habilitada en compilaciones de prueba.

Recomendamos habilitar MTE en modo síncrono en todos los objetos binarios nativos durante el desarrollo

SANITIZE_TARGET=memtag_heap SANITIZE_TARGET_DIAG=memtag_heap m

Al igual que con cualquier variable del sistema de compilación, SANITIZE_TARGET puede como una variable de entorno o una configuración make (por ejemplo, en un archivo product.mk).
Ten en cuenta que esto habilita MTE para todos los procesos nativos, pero no para apps (que se bifurcan a partir de zygote64) para las que se puede usar MTE habilitado siguiendo las instrucciones anteriores.

Cómo configurar el nivel de MTE preferido específico de la CPU

En algunas CPU, el rendimiento de MTE en ASYMM o incluso en los modos SYNC puede ser similar al siguiente: el de ASYNC. Esto hace que valga la pena habilitar verificaciones más estrictas en esas CPU cuando se solicita un modo de comprobación menos estricto, en para obtener los beneficios de detección de errores de verificaciones más estrictas sin la y las desventajas en el rendimiento.
De forma predeterminada, los procesos configurados para ejecutarse en modo ASYNC se ejecutarán en ASYNC en todas las CPU. Para configurar el kernel de modo que ejecute estos procesos en el modo SYNC en CPU específicas, el valor de la sincronización debe escribirse en sysfs entrada /sys/devices/system/cpu/cpu<N>/mte_tcf_preferred en el inicio tiempo. Esto se puede hacer con una secuencia de comandos init. Por ejemplo, para configurar las CPU 0-1 para ejecutar los procesos del modo ASYNC en modo SYNC, y las CPU 2-3 para usar en modo ASYMM se puede agregar lo siguiente a la cláusula init de una secuencia de comandos init del proveedor:

  write /sys/devices/system/cpu/cpu0/mte_tcf_preferred sync
  write /sys/devices/system/cpu/cpu1/mte_tcf_preferred sync
  write /sys/devices/system/cpu/cpu2/mte_tcf_preferred asymm
  write /sys/devices/system/cpu/cpu3/mte_tcf_preferred asymm

Las tombstones de los procesos del modo ASYNC que se ejecutan en modo SYNC contendrán un un seguimiento de pila preciso de la ubicación del error de memoria. Sin embargo, no incluir un seguimiento de pila de asignación o desasignación. Estos seguimientos de pila solo son disponible si el proceso está configurado para ejecutarse en modo SYNC.

int mallopt(M_THREAD_DISABLE_MEM_INIT, level)

donde level es 0 o 1.
Inhabilita la inicialización de la memoria en malloc y evita cambiar las etiquetas de memoria a menos que sea necesario para que haya precisión.

int mallopt(M_MEMTAG_TUNING, level)

donde level es:

  • M_MEMTAG_TUNING_BUFFER_OVERFLOW
  • M_MEMTAG_TUNING_UAF

Selecciona la estrategia de asignación de etiquetas.

  • La configuración predeterminada es M_MEMTAG_TUNING_BUFFER_OVERFLOW.
  • M_MEMTAG_TUNING_BUFFER_OVERFLOW: habilita determinística. detección de errores de desbordamiento y subdesbordamiento del búfer lineal asignando etiquetas distintas de salida a asignaciones adyacentes. Este modo tiene una probabilidad ligeramente reducida de detectar errores de uso después de la liberación, ya que solo se disponibles para cada ubicación de memoria. Ten en cuenta que MTE no puede detectar desborde dentro del mismo gránulo de etiqueta (fragmento alineado de 16 bytes) y puede pasar por alto pequeñas se desborde incluso en este modo. Ese desbordamiento no puede ser la causa de la debido a que la memoria de un gránulo nunca se usa para múltiples asignaciones de recursos.
  • M_MEMTAG_TUNING_UAF: Habilita etiquetas aleatorias de forma independiente. para una probabilidad uniforme de aproximadamente un 93% de detección espacial (desbordamiento del búfer) y errores temporales (usar después de la liberación).

Además de las APIs descritas anteriormente, los usuarios con experiencia pueden querer tengan en cuenta lo siguiente:

  • Configurar el registro de hardwarePSTATE.TCO puede suprimir la comprobación de etiquetas (ejemplo). (por ejemplo, cuando se copia un rango de memoria con contenido de etiquetas desconocido). y abordar un cuello de botella del rendimiento en un bucle caliente.
  • Cuando usas M_HEAP_TAGGING_LEVEL_SYNC, el controlador de fallas del sistema proporciona información adicional, como seguimientos de pila de asignación y desasignación. Esta funcionalidad requiere acceso a los bits de la etiqueta y se habilita pasando el SA_EXPOSE_TAGBITS cuando configures el controlador de señales. Cualquier programa que establezca su propio indicador y delega las fallas desconocidas al sistema, se recomienda hacer lo siguiente: igual.

MTE en el kernel

Para habilitar KASAN acelerado por MTE para el kernel, configúralo con CONFIG_KASAN=y y CONFIG_KASAN_HW_TAGS=y. Estos parámetros de configuración están habilitadas de forma predeterminada en los kernels de GKI, comenzando por Android 12-5.10.
Esto se puede controlar en el momento del inicio con los siguientes argumentos de línea de comandos:

  • kasan=[on|off]: habilita o inhabilita KASAN (valor predeterminado: on)
  • kasan.mode=[sync|async]: elegir entre el modo síncrono y asíncrono (configuración predeterminada: sync)
  • kasan.stacktrace=[on|off]: si se debe recopilar o no seguimientos de pila (valor predeterminado: on)
    • la recopilación de seguimiento de pila también requiere stack_depot_disable=off
  • kasan.fault=[report|panic]: Indica si solo se imprimirá el informe. o generar un error en el kernel (valor predeterminado: report). Independientemente de opción, la verificación de etiquetas se inhabilita después del primer error informado.
.

Recomendamos usar el modo SYNC durante la introducción, el desarrollo y y pruebas. Esta opción debe habilitarse de manera global para todos los procesos que usan la variable de entorno o el sistema de compilación. En este modo, se detectan errores en las primeras etapas del proceso de desarrollo, la base de código se estabiliza más rápido y el costo de detectar errores más adelante en la producción.

Recomendamos usar el modo ASYNC en producción. Esto proporciona una baja herramienta de sobrecarga para detectar la presencia de errores de seguridad de la memoria en un proceso, como así como una mayor defensa en profundidad. Una vez que se detecta un error, el desarrollador puede Aprovecha las APIs del entorno de ejecución para cambiar al modo SYNC y obtener un seguimiento de pila preciso de un conjunto de usuarios de la muestra.

Recomendamos enfáticamente configurar el nivel de MTE preferido específico de la CPU para el SoC. El modo asymm suele tener las mismas características de rendimiento que ASYNC. y casi siempre es preferible a ella. Los núcleos pequeños en orden suelen mostrar resultados rendimiento en los tres modos, y se puede configurar para preferir SYNC.

Los desarrolladores deben comprobar la presencia de fallas revisando /data/tombstones, logcat o supervisando el proveedor DropboxManager para los errores de los usuarios finales. Para obtener más información sobre la depuración de código nativo de Android, consulta aquí.

Componentes de la plataforma habilitados para MTE

En Android 12, varios componentes críticos del sistema para la seguridad usan MTE ASYNC para detectar fallas de los usuarios finales y actuar como una capa adicional de de defensa en profundidad. Estos componentes son los siguientes:

  • Daemons y utilidades de red (con la excepción de netd)
  • Bluetooth, SecureElement, HALs de NFC y apps del sistema
  • Daemon de statsd
  • system_server
  • zygote64 (para permitir que las apps habiliten el uso de MTE)

Estos objetivos se seleccionaron según los siguientes criterios:

  • Un proceso con privilegios (definido como un proceso que tiene acceso a algo que el dominio SELinux de unprivileged_app no).
  • Procesa entradas no confiables (regla de dos)
  • Reducción aceptable del rendimiento (la demora no hace que el usuario sea visible) latencia)

Alentamos a los proveedores a habilitar MTE en producción para más componentes siguiendo los criterios mencionados anteriormente. Durante el desarrollo, recomendamos realizar pruebas estos componentes usando el modo SYNC para detectar errores fácilmente corregidos y evaluar la el impacto de ASYNC en su rendimiento.
En el futuro, Android planea ampliar la lista de componentes del sistema MTE habilitado, guiado por las características de rendimiento de los próximos diseños de hardware.