escudo

Scudo es un asignador de memoria dinámico en modo de usuario, o asignador de montón , diseñado para ser resistente frente a vulnerabilidades relacionadas con el montón (como el desbordamiento del búfer basado en montón , el uso después de la liberación y la doble liberación ) manteniendo al mismo tiempo el rendimiento. Proporciona las primitivas de asignación y desasignación de C estándar (como malloc y free), así como las primitivas de C++ (como nuevas y eliminar).

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

Desde el lanzamiento 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 del montón 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 montón.

Scudo es de código abierto y forma 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ó soporte a Soong y Make para permitir una fácil habilitación del asignador en un binario.

Puede habilitar o deshabilitar la mitigación adicional dentro del asignador usando 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 que se analizará. Esta función debe tener el siguiente prototipo: extern "C" const char *__scudo_default_options() .
  • Dinámicamente: utilice 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 mediante __scudo_default_options .

Las siguientes opciones están disponibles.

Opción Valor predeterminado de 64 bits Valor 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 esto y ThreadLocalQuarantineSizeKb en cero deshabilita 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 caché por subproceso para descargar la cuarentena global. Un valor más bajo puede reducir el uso de memoria, pero puede aumentar la contención en la cuarentena global. Establecer tanto esto como QuarantineSizeKb en cero deshabilita la cuarentena por completo.
DeallocationTypeMismatch false false Habilita el informe de errores en malloc/delete, new/free, new/delete[]
DeleteSizeMismatch true true Habilita informes de errores sobre discrepancias entre los tamaños de nuevo y eliminado.
ZeroContents false false Habilita contenido de fragmentos cero 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 desactivarse para permitir nuevas asignaciones.
allocator_release_to_os_interval_ms N / A 5000 Sólo afecta a un asignador de 64 bits. Si está configurado, intenta liberar memoria no utilizada al sistema operativo, pero no con más frecuencia que este intervalo (en milisegundos). Si el valor es negativo, la memoria no se libera al sistema operativo.
abort_on_error true true Si está configurada, la herramienta llama abort() en lugar de _exit() después de imprimir el mensaje de error.

Validación

Actualmente, no existen 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 determinado para verificar que no afecte al 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. El resultado generalmente comienza con Scudo ERROR: seguido de un breve resumen del problema junto con sugerencias.

A continuación se muestra una lista de los mensajes de error actuales y sus posibles causas:

  • corrupted chunk header : la verificación de la suma de comprobación del encabezado del 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 sintomático de una condición de carrera o de una falta general de bloqueo al realizar operaciones en ese fragmento.
  • invalid chunk state : el fragmento no está en el estado esperado para una operación determinada; por ejemplo, no está asignado cuando se intenta liberarlo o no se pone en cuarentena cuando se intenta reciclarlo. Un doble gratis es la razón típica de este error.
  • misaligned pointer : se aplican estrictamente los requisitos de alineación básicos: 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 no está alineado.
  • allocation type mismatch : cuando esta opción está habilitada, una función de desasignación llamada en un fragmento debe coincidir con el tipo de función que se llamó para asignarlo. Este tipo de discrepancia puede introducir problemas de seguridad.
  • invalid sized delete : cuando se utiliza 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. Esto suele ser un problema del compilador o una confusión de tipos en el objeto que se está desasignando.
  • RSS limit exhausted : se ha excedido el máximo de RSS especificado opcionalmente.

Si está depurando un fallo en el sistema operativo, puede utilizar una compilación del sistema operativo HWASan . Si está depurando un fallo en una aplicación, también es posible utilizar una compilación de aplicación HWASan .