escudo

Scudo es un asignador de memoria dinámico en modo de usuario, o asignador de montón , diseñado para resistir las vulnerabilidades relacionadas con el montón (como el desbordamiento de búfer basado en montón, el uso después de liberar y el doble libre ) mientras mantiene el rendimiento. Proporciona las primitivas estándar de asignación y desasignación de C (como malloc y free), así como las primitivas de C++ (como new y delete).

Scudo es más una mitigación que un detector de errores de memoria completo como AddressSanitizer (ASan) .

A partir de la versión de Android 11, scudo se usa para todo el código nativo (excepto en dispositivos con poca memoria, donde todavía se usa jemalloc). En tiempo de ejecución, Scudo atiende todas las asignaciones y desasignaciones de almacenamiento dinámico nativo para todos los ejecutables y sus dependencias de biblioteca, y el proceso se cancela si se detecta corrupción o comportamiento sospechoso en el almacenamiento dinámico.

En Android 10, scudo tenía que habilitarse por binario configurando la LOCAL_SANITIZE := scudo en el archivo .mk o sanitize: { scudo: true, } en el archivo .bp.

Scudo es de código abierto y parte del proyecto compilador-rt de LLVM. La documentación está disponible en https://llvm.org/docs/ScudoHardenedAllocator.html . El tiempo de ejecución de Scudo se envía como parte de la cadena de herramientas de Android y se agregó compatibilidad con Soong y Make para permitir una habilitación sencilla del asignador en un binario.

Puede habilitar o deshabilitar la mitigación adicional dentro del asignador mediante las opciones que se describen a continuación.

personalización

Algunos parámetros del asignador se pueden definir por proceso de varias maneras:

  • Estáticamente: defina una función __scudo_default_options en el programa que devuelva la cadena de opciones para analizar. Esta función debe tener el siguiente prototipo: extern "C" const char *__scudo_default_options() .
  • Dinámicamente: use la variable de entorno SCUDO_OPTIONS que contiene la cadena de opciones que se va a analizar. Las opciones definidas de esta manera anulan cualquier definición realizada a través __scudo_default_options .

Las siguientes opciones están disponibles.

Opción predeterminado de 64 bits predeterminado de 32 bits Descripción
QuarantineSizeKb 256 64 El tamaño (en KB) de la cuarentena utilizada para retrasar la desasignación real de fragmentos. Un valor más bajo puede reducir el uso de memoria pero disminuir la efectividad de la mitigación; un valor negativo vuelve a los valores predeterminados. Establecer tanto esto como ThreadLocalQuarantineSizeKb en cero desactiva la cuarentena por completo.
QuarantineChunksUpToSize 2048 512 El tamaño (en bytes) hasta el cual se pueden poner en cuarentena los fragmentos.
ThreadLocalQuarantineSizeKb 64 16 El tamaño (en KB) del uso de la memoria caché por subproceso para descargar la cuarentena global. Un valor más bajo puede reducir el uso de la memoria, pero puede aumentar la contención en la cuarentena global. Establecer tanto esto como QuarantineSizeKb en cero desactiva la cuarentena por completo.
DeallocationTypeMismatch false false Habilita el informe de errores en malloc/delete, new/free, new/delete[]
DeleteSizeMismatch true true Habilita el informe de errores sobre la falta de coincidencia entre los tamaños de nuevo y eliminado.
ZeroContents false false Habilita el contenido de cero fragmentos en la asignación y desasignación.
allocator_may_return_null false false Especifica que el asignador puede devolver un valor nulo cuando se produce un error recuperable, en lugar de finalizar el proceso.
hard_rss_limit_mb 0 0 Cuando el RSS del proceso alcanza este límite, el proceso finaliza.
soft_rss_limit_mb 0 0 Cuando el RSS del proceso alcanza este límite, las asignaciones adicionales fallan o devuelven un null (según el valor de allocator_may_return_null ), hasta que el RSS vuelve a bajar para permitir nuevas asignaciones.
allocator_release_to_os_interval_ms N / A 5000 Solo afecta a un asignador de 64 bits. Si está configurado, intenta liberar la memoria no utilizada al sistema operativo, pero no más a menudo que este intervalo (en milisegundos). Si el valor es negativo, la memoria no se libera al sistema operativo.
abort_on_error true true Si se establece, la herramienta llama a abort() en lugar de _exit() después de imprimir el mensaje de error.

Validación

Actualmente, no hay pruebas CTS específicas para Scudo. En su lugar, asegúrese de que las pruebas CTS pasen con o sin Scudo habilitado para un binario dado para verificar que no afecte el dispositivo.

Solución de problemas

Si se detecta un problema no recuperable, el asignador muestra un mensaje de error en el descriptor de error estándar y luego finaliza el proceso. Los seguimientos de pila que conducen a la terminación se agregan en el registro del sistema. La salida generalmente comienza con Scudo ERROR: seguido de un breve resumen del problema junto con cualquier sugerencia.

Aquí hay una lista de los mensajes de error actuales y sus posibles causas:

  • Encabezado de corrupted chunk header : la verificación de la suma de comprobación del encabezado de fragmento ha fallado. Es probable que esto se deba a una de dos cosas: el encabezado se sobrescribió (parcial o totalmente) o el puntero pasado a la función no es un fragmento.
  • race on chunk header : dos subprocesos diferentes intentan manipular el mismo encabezado al mismo tiempo. Esto suele ser un síntoma de una condición de carrera o una falta general de bloqueo al realizar operaciones en ese fragmento.
  • invalid chunk state : el fragmento no se encuentra en el estado esperado para una operación determinada; por ejemplo, no se asigna al intentar liberarlo o no se pone en cuarentena al intentar reciclarlo. Un doble gratis es la razón típica de este error.
  • misaligned pointer : los requisitos básicos de alineación se aplican estrictamente: 8 bytes en plataformas de 32 bits y 16 bytes en plataformas de 64 bits. Si un puntero pasado a nuestras funciones no se ajusta a ellas, el puntero pasado a una de las funciones está desalineado.
  • allocation type mismatch : cuando esta opción está habilitada, una función de desasignación invocada en un fragmento debe coincidir con el tipo de función que se invocó para asignarlo. Este tipo de desajuste puede presentar problemas de seguridad.
  • invalid sized delete : cuando se usa el operador de eliminación de tamaño C++14 y la verificación opcional está habilitada, hay una discrepancia entre el tamaño que se pasó al desasignar un fragmento y el tamaño que se solicitó al asignarlo. Suele ser un problema del compilador o una confusión de tipos en el objeto que se desasigna.
  • RSS limit exhausted : Se ha excedido el RSS máximo especificado opcionalmente.

Si está depurando un bloqueo en el propio sistema operativo, puede usar una compilación de sistema operativo HWASan . Si está depurando un bloqueo en una aplicación, también es posible usar una compilación de aplicación HWASan .