Depuración y mitigación de errores de memoria

Android admite varias herramientas para depurar errores de memoria. Cada una tiene sus ventajas y desventajas, por lo que te recomendamos que leas la siguiente información para decidir cuál es la mejor según tu caso de uso. En este documento, se brinda una descripción general de las herramientas disponibles para que puedas decidir cuál investigar más a fondo. Sin embargo, este es un resumen y sugerimos leer los documentos específicos de las herramientas para obtener más detalles.

Resumen

  • Usa un lenguaje seguro para la memoria siempre que sea posible para imposibilitar los errores de memoria.
  • Usa siempre PAC/BTI para mitigar los ataques de ROP/JOP.
  • Usa siempre GWP-ASan para detectar errores de memoria poco comunes en producción.
  • Usa HWASan para detectar errores de memoria durante las pruebas.
  • Los dispositivos compatibles con MTE no tienen disponibilidad general en 2023, pero úsala si puedes detectar errores en producción.
  • Usa ASan durante la prueba solo como último recurso.

Lenguajes seguros para la memoria

Un lenguaje seguro para la memoria es la única forma de evitar y mitigar por completo los errores de memoria. Las otras herramientas que figuran en esta página pueden ayudarte a que el código no seguro para tu memoria sea más seguro y confiable, pero usar un lenguaje seguro para la memoria elimina toda clase de problemas.

Los lenguajes seguros para la memoria compatibles oficialmente con Android son Java y Kotlin. La mayoría de las aplicaciones para Android son más fáciles de desarrollar en uno de esos lenguajes.

Sin embargo, hay desarrolladores de apps que envían código escrito en Rust y, si estás leyendo esta página, es probable que tengas un buen motivo para necesitar código nativo (portabilidad, rendimiento o ambos). Rust es la mejor opción para obtener código nativo seguro para la memoria en Android. El equipo del NDK no puede ayudarte con los problemas a los que te enfrentes si sigues ese camino, pero nos interesa conocerlos.

PAC/BTI

La autenticación de puntero y la identificación de destino de la rama, también conocidas como PAC/BTI, son herramientas de mitigación adecuadas para su uso en la producción. Si bien son tecnologías independientes, se controlan con la misma marca del compilador, por lo que siempre se usan juntas.

Estas funciones son retrocompatibles con dispositivos que no las admiten porque las instrucciones nuevas que se usan son no-ops en dispositivos anteriores. También es necesario tener un kernel y una versión del SO lo suficientemente nuevos. Buscar paca y bti en /proc/cpuinfo te muestra si tienes un hardware y un kernel lo suficientemente nuevos Android 12 (nivel de API 31) tiene la compatibilidad necesaria con el espacio de usuario.

Ventajas:

  • Se puede habilitar en todas las compilaciones sin causar problemas en dispositivos o kernels más antiguos (pero asegúrate de realizar pruebas en una combinación de dispositivo, kernel o SO que lo admita).

Desventajas:

  • Solo está disponible para apps de 64 bits.
  • No mitiga errores en dispositivos que no son compatibles.
  • Genera una sobrecarga del tamaño del código del 1%.

GWP-Asan

Se puede usar GWP-ASan para detectar errores de memoria en el campo, pero la tasa de muestreo es demasiado baja para constituir una mitigación eficaz.

Ventajas:

  • No genera una sobrecarga significativa de CPU ni de memoria.
  • Es muy fácil de implementar: no requiere volver a compilar código nativo.
  • Funciona con apps de 32 bits.

Desventajas:

  • Una tasa de muestreo baja requiere una gran cantidad de usuarios para encontrar errores de manera eficaz.
  • Solo detecta errores de montón, no de pila.

HWASan

El limpiador de direcciones de hardware, también conocido como HWASan, es la mejor opción para detectar errores de memoria durante las pruebas. Resulta más útil cuando se usa con pruebas automatizadas, especialmente si ejecutas pruebas de fuzz. Sin embargo, según las necesidades de rendimiento de la app, también se puede usar en teléfonos de alta gama en una configuración de prueba interna.

Ventajas:

  • No arroja falsos positivos.
  • Detecta clases adicionales de errores que ASan no puede (uso de pila después de la devolución).
  • Tiene una menor tasa de falsos negativos que MTE (1 de 256 en comparación con 1 de 16).
  • Tiene menor sobrecarga de memoria que ASan, su alternativa más cercana,

Desventajas:

  • Genera una sobrecarga significativa de la CPU (~100%), tamaño del código (~50%) y memoria (del 10% al 35%).
  • Hasta el nivel de API 34 y la versión r26 de NDK, se requiere escribir en la memoria flash una imagen compatible con HWASan.
  • Solo funciona en apps de 64 bits.

MTE

La extensión de etiquetado de memoria, también conocida como MTE, es una alternativa de menor costo que HWASan. Además de las capacidades de depuración y prueba, se puede usar para detectar y mitigar la corrupción de la memoria en la producción. Si tienes el hardware para probar las compilaciones de MTE, debes habilitarlo.

Ventajas:

  • La sobrecarga es lo suficientemente baja para que se pueda tolerar en la producción de muchas apps.
  • No arroja falsos positivos.
  • No requiere volver a compilar el código para detectar errores de montón (sí para detectar errores de pila).

Desventajas:

  • No hay dispositivos comercialmente disponibles que tengan MTE habilitada de forma predeterminada en 2024, pero en la documentación de Arm se explica cómo habilitar MTE para realizar pruebas en Pixel 8 o Pixel 8 Pro.
  • Tiene una tasa de falsos negativos de 1 de 16 en comparación con la de HWASan de 1 de 256.
  • Solo está disponible para apps de 64 bits.
  • Se requiere la compilación de bibliotecas independientes para orientar a dispositivos habilitados y no habilitados para MTE.

ASan

Address Sanitizer, también conocida como ASan, es la herramienta más antigua y más disponible de todas. Resulta útil para detectar errores de memoria durante pruebas y problemas de depuración que solo afectan a dispositivos antiguos en los que ninguna de las otras herramientas está disponible. Siempre que sea posible, es preferible usar HWASan.

Ventajas:

  • Tiene gran disponibilidad. Puede funcionar en dispositivos tan antiguos como KitKat.
  • No arroja falsos positivos ni negativos cuando se utiliza correctamente.

Desventajas:

  • Es difícil de compilar y empaquetar correctamente.
  • Produce la sobrecarga más alta entre todas las opciones: ~100% de CPU, ~50% del tamaño del código y ~100% de uso de memoria.
  • Ya no se admite.
  • Tiene errores conocidos que no se solucionarán.