Fortalecimiento de la seguridad basado en datos en Android


El equipo de la plataforma Android se compromete a proteger Android para todos los usuarios en todos los dispositivos. Además de actualizaciones de seguridad mensuales para parchear las vulnerabilidades que nos informan a través de nuestro Programa de recompensas por vulnerabilidad (VRP), también diseñamos Android de manera proactiva para protegerlo contra vulnerabilidades no descubiertas mediante medidas de refuerzo como la aplicación mitigaciones basadas en compilador y mejora de la zona de pruebas. Esta publicación se centra en el proceso de toma de decisiones que entra en estas medidas proactivas: en particular, cómo elegimos qué técnicas de refuerzo implementar y dónde se implementan. Como las capacidades de los dispositivos varían ampliamente dentro del ecosistema de Android, estas decisiones deben tomarse con cuidado, guiadas por los datos disponibles para nosotros para maximizar el valor del ecosistema en su conjunto.

El enfoque general de la seguridad de Android es múltiple y aprovecha varios principios y técnicas para llegar a soluciones guiadas por datos que dificulten la explotación futura. En particular, cuando se trata de fortalecer la plataforma, intentamos responder las siguientes preguntas:

  • ¿Qué datos están disponibles y cómo pueden guiar las decisiones de seguridad?
  • ¿Qué mitigaciones están disponibles, cómo se pueden mejorar y dónde deberían habilitarse?
  • ¿Cuáles son los desafíos de implementación de determinadas mitigaciones y qué compensaciones hay que considerar?

Al arrojar algo de luz sobre el proceso que usamos para elegir las funciones de seguridad para Android, esperamos brindar una mejor comprensión del enfoque general de Android para proteger a nuestros usuarios.

Toma de decisiones de seguridad basada en datos

Usamos una variedad de fuentes para determinar qué áreas de la plataforma se beneficiarían más de los diferentes tipos de mitigaciones de seguridad. los Programa de recompensas por vulnerabilidades de Android (VRP) es una fuente muy informativa: nuestros ingenieros de seguridad analizan todas las vulnerabilidades enviadas a través de este programa para determinar la causa raíz de cada vulnerabilidad y su gravedad general (según estas pautas). Otras fuentes son informes de errores internos y externos, que identifican componentes vulnerables y revelan prácticas de codificación que comúnmente conducen a errores. El conocimiento de los patrones de código problemáticos combinado con la prevalencia y la gravedad de las vulnerabilidades que causan puede ayudar a informar las decisiones sobre qué mitigaciones probablemente sean las más beneficiosas.


Tipos de vulnerabilidades críticas y de alta gravedad corregidas en los boletines de seguridad de Android en 2019

Depender únicamente de los informes de vulnerabilidad no es suficiente ya que los datos están intrínsecamente sesgados: a menudo, los investigadores de seguridad acuden en masa a áreas "calientes", donde otros investigadores ya han encontrado vulnerabilidades (p. Ej. Miedo escénico). O pueden centrarse en áreas donde las herramientas fácilmente disponibles facilitan la búsqueda de errores (por ejemplo, si se publica una herramienta de investigación de seguridad en Github, otros investigadores suelen utilizar esa herramienta para explorar más a fondo).

Para asegurarse de que los esfuerzos de mitigación no estén sesgados solo hacia áreas donde se han informado errores y vulnerabilidades, los Equipos Rojos internos analizan partes menos escrutadas o más complejas de la plataforma. Además, los fuzzers automáticos continuos se ejecutan a escala tanto en máquinas virtuales como en dispositivos físicos de Android. Esto también garantiza que los errores se puedan encontrar y corregir al principio del ciclo de vida del desarrollo. Las vulnerabilidades descubiertas a través de este proceso también se analizan para determinar la causa raíz y la gravedad, que informan las decisiones de implementación de mitigación.

El VRP de Android recompensa las presentaciones de cadenas de explotación completas que demuestran un ataque completo de un extremo a otro. Estas cadenas de exploits, que generalmente utilizan múltiples vulnerabilidades, son muy informativas para demostrar las técnicas que los atacantes utilizan para encadenar las vulnerabilidades para lograr sus objetivos. Siempre que un investigador envía una cadena de exploits completa, un equipo de ingenieros de seguridad analiza y documenta el enfoque general, cada eslabón de la cadena y cualquier estrategia de ataque innovadora utilizada. Este análisis informa qué estrategias de mitigación de exploits podrían emplearse para evitar la transición directa de una vulnerabilidad a otra (algunos ejemplos incluyen Aleatorización del diseño del espacio de direcciones y Integridad de flujo de control) y si la superficie de ataque del proceso podría reducirse si tiene acceso innecesario a los recursos.

A menudo hay varias formas diferentes de utilizar una colección de vulnerabilidades para crear una cadena de exploits. Por lo tanto, un enfoque de defensa en profundidad es beneficioso, con el objetivo de reducir la utilidad de algunas vulnerabilidades y alargar las cadenas de explotación para que la explotación exitosa requiera más vulnerabilidades. Esto aumenta el costo para que un atacante desarrolle una cadena de exploits completa.

Mantenernos al día con los desarrollos en la comunidad de seguridad en general nos ayuda a comprender el panorama actual de amenazas, qué técnicas se utilizan actualmente para la explotación y cómo son las tendencias futuras. Esto incluye, pero no se limita a:

  • Estrecha colaboración con la comunidad de investigación de seguridad externa
  • Leer revistas y asistir a conferencias
  • Técnicas de monitoreo utilizadas por malware
  • Seguir las tendencias de investigación de seguridad en comunidades de seguridad
  • Participar en esfuerzos y proyectos externos como KSPP, syzbot, LLVM, Rust y más

Todas estas fuentes de datos brindan retroalimentación para la estrategia general de fortalecimiento de la seguridad, dónde se deben implementar nuevas mitigaciones y qué mitigaciones de seguridad existentes deben mejorarse.

Razonamiento sobre el endurecimiento de la seguridad

Endurecimiento y mitigaciones

El análisis de los datos revela áreas donde las mitigaciones más amplias pueden eliminar clases enteras de vulnerabilidades. Por ejemplo, si partes de la plataforma muestran una gran cantidad de vulnerabilidades debido a errores de desbordamiento de enteros, son buenos candidatos para habilitar Undefined Behavior Sanitizer (UBSan) mitigaciones como Integer Overflow Sanitizer. Cuando aparecen patrones comunes en las vulnerabilidades de acceso a la memoria, informan los esfuerzos para construir asignadores de memoria reforzados (habilitado por defecto en Android 11) e implementar mitigaciones (como CFI) contra técnicas de explotación que brindan una mejor resistencia frente a desbordamientos de memoria o vulnerabilidades de uso posterior a la liberación.

Antes de discutir cómo se pueden usar los datos, es importante comprender cómo clasificamos nuestros esfuerzos generales para fortalecer la plataforma. Hay algunos segmentos ampliamente definidos en los que encajan las técnicas de refuerzo y las mitigaciones (aunque a veces una mitigación en particular puede no encajar claramente en uno solo):

  • Explotar mitigaciones
    • Prevención de vulnerabilidades determinista en tiempo de ejecución detecta un comportamiento indefinido o inesperado y aborta la ejecución cuando se detecta el comportamiento. Esto convierte las posibles vulnerabilidades de corrupción de la memoria en bloqueos menos dañinos. A menudo, estas mitigaciones se pueden habilitar de forma selectiva y seguir siendo eficaces porque afectan a errores individuales. Ejemplos incluyen Desinfectante Entero y Límites Desinfectante.
    • Mitigaciones de técnicas de explotación apuntar a las técnicas utilizadas para pasar de una vulnerabilidad a otra o para obtener la ejecución del código. En teoría, estas mitigaciones pueden hacer que algunas vulnerabilidades sean inútiles, pero más a menudo sirven para restringir las acciones disponibles para los atacantes que buscan explotar las vulnerabilidades. Esto aumenta la dificultad del desarrollo de exploits en términos de tiempo y recursos. Es posible que estas mitigaciones deban habilitarse en todo el espacio de memoria de un proceso para que sean efectivas. Los ejemplos incluyen la aleatorización del diseño del espacio de direcciones, la integridad del flujo de control (CFI), los canarios de pila y el etiquetado de memoria.
    • Transformaciones del compilador que cambian el comportamiento indefinido a un comportamiento definido en tiempo de compilación. Esto evita que los atacantes se aprovechen de comportamientos indefinidos como memoria no inicializada. Un ejemplo de esto es la inicialización de la pila.
  • Descomposición arquitectónica
    • Divide los componentes más grandes y privilegiados en partes más pequeñas, cada una de las cuales tiene menos privilegios que el original. Después de esta descomposición, una vulnerabilidad en uno de los componentes más pequeños tendrá una gravedad reducida al proporcionar menos acceso al sistema, alargar las cadenas de exploits y dificultar que un atacante obtenga acceso a datos confidenciales o rutas de escalada de privilegios adicionales.
  • Sandboxing / aislamiento
    • Relacionado con la descomposición arquitectónica, impone un conjunto mínimo de permisos / capacidades que un proceso necesita para funcionar correctamente, a menudo a través del control de acceso obligatorio y / o discrecional. Al igual que la descomposición arquitectónica, esto hace que las vulnerabilidades en estos procesos sean menos valiosas ya que hay menos cosas que los atacantes pueden hacer en ese contexto de ejecución, aplicando el principio de privilegios mínimos. Algunos ejemplos son Permisos de Android, Permisos de Unix, Capacidades de Linux, SELinuxy Seccomp.
  • Migrar a lenguajes seguros para la memoria
    • C y C ++ no brindan seguridad a la memoria de la forma en que lo hacen lenguajes como Java, Kotlin y Rust. Dado que el mayoria de las vulnerabilidades de seguridad informadas a Android son problemas de seguridad de la memoria, se aplica un enfoque doble: mejorar la seguridad de C / C ++ al mismo tiempo que se fomenta el uso de lenguajes seguros para la memoria.

Habilitando estas mitigaciones

Con el amplio arsenal de técnicas de mitigación disponibles, cuál de ellas emplear y dónde aplicarlas depende del tipo de problema que se resuelva. Por ejemplo, un proceso monolítico que maneja una gran cantidad de datos que no son de confianza y realiza un análisis complejo sería un buen candidato para todos estos. Los marcos de medios proporcionan un excelente ejemplo histórico en el que una descomposición arquitectónica permitió activar gradualmente más mitigaciones y desprivilegios de exploits.

Descomposición arquitectónica y aislamiento de los Media Frameworks a lo largo del tiempo

Las superficies de ataque accesibles de forma remota como NFC, Bluetooth, WiFi y componentes de medios han albergado históricamente las vulnerabilidades más graves y, como tales, estos componentes también tienen prioridad para el endurecimiento. Estos componentes a menudo contienen algunas de las causas de raíz de vulnerabilidad más comunes que se informan en el VRP, y recientemente habilitamos desinfectantes en todos ellos.

Bibliotecas y procesos que imponen o se sitúan en los límites de seguridad, como libbinder, y bibliotecas centrales ampliamente utilizadas como libui, libcorey libcutils son buenos objetivos para las mitigaciones de exploits, ya que no son específicos del proceso. Sin embargo, debido a las sensibilidades de rendimiento y estabilidad en torno a estas bibliotecas centrales, las mitigaciones deben estar respaldadas por pruebas sólidas de su impacto en la seguridad.

Finalmente, el alto nivel de privilegios del kernel lo convierte también en un objetivo importante para el endurecimiento. Debido a que las diferentes bases de código tienen características y funcionalidades diferentes, la susceptibilidad y la prevalencia de ciertos tipos de vulnerabilidades serán diferentes. La estabilidad y el rendimiento de las mitigaciones aquí son excepcionalmente importantes para evitar un impacto negativo en la experiencia del usuario, y algunas mitigaciones que tienen sentido implementar en el espacio del usuario pueden no ser aplicables o efectivas. Por lo tanto, nuestras consideraciones sobre qué estrategias de endurecimiento emplear en el kernel se basan en un análisis separado de los datos específicos del kernel disponibles.

Este enfoque basado en datos ha dado lugar a resultados tangibles y mensurables. A partir de 2015 con Stagefright, un gran número de Severidad crítica Se informaron vulnerabilidades en el marco de medios de Android. Estos eran especialmente sensibles porque muchas de estas vulnerabilidades eran accesibles de forma remota. Esto llevó a un gran esfuerzo de descomposición arquitectónica en Android Nougat, seguido de esfuerzos adicionales para mejorar nuestra capacidad para reparar las vulnerabilidades de los medios rápidamente. Gracias a estos cambios, en 2020 no se nos informaron vulnerabilidades de gravedad crítica accesibles en Internet en los marcos de medios.

Consideraciones de implementación

Algunas de estas mitigaciones proporcionan más valor que otras, por lo que es importante concentrar los recursos de ingeniería donde sean más efectivos. Esto implica sopesar el costo de rendimiento de cada mitigación, así como la cantidad de trabajo que se requiere para implementarla y respaldarla sin afectar negativamente la estabilidad del dispositivo o la experiencia del usuario.

Actuación

Comprender el impacto en el rendimiento de una mitigación es un paso fundamental para habilitarla. Agregar demasiada sobrecarga a algunos componentes o al sistema completo puede afectar negativamente la experiencia del usuario al reducir la duración de la batería y hacer que el dispositivo responda menos. Esto es especialmente cierto para los dispositivos de nivel de entrada, que también deberían beneficiarse del endurecimiento. Por lo tanto, queremos priorizar los esfuerzos de ingeniería en mitigaciones impactantes con gastos generales aceptables.

Al investigar el rendimiento, los factores importantes incluyen no solo el tiempo de la CPU, sino también el aumento de la memoria, el tamaño del código, la duración de la batería y IU jank. Es especialmente importante tener en cuenta estos factores para los dispositivos de nivel de entrada más restringidos, para garantizar que las mitigaciones funcionen bien en todo el ecosistema de Android.

El impacto de una mitigación en el rendimiento de todo el sistema también depende de dónde se habilite esa mitigación, ya que ciertos componentes son más sensibles al rendimiento que otros. Por ejemplo, Binder es una de las rutas más utilizadas para la comunicación entre procesos, por lo que incluso una pequeña sobrecarga adicional podría afectar significativamente la experiencia del usuario en un dispositivo. Por otro lado, los reproductores de video solo necesitan asegurarse de que los fotogramas se procesen a la velocidad de fotogramas de origen; si los fotogramas se procesan mucho más rápido que la velocidad a la que se muestran, la sobrecarga adicional puede ser más aceptable.

Los puntos de referencia, si están disponibles, pueden ser extremadamente útiles para evaluar el impacto en el desempeño de una mitigación. Si no hay puntos de referencia para un determinado componente, se deben crear nuevos, por ejemplo, llamando al código del códec afectado para decodificar un archivo multimedia. Si esta prueba revela una sobrecarga inaceptable, a menudo hay algunas opciones para abordarla:

  • Desactive selectivamente la mitigación en funciones sensibles al rendimiento identificadas durante las evaluaciones comparativas. Una pequeña cantidad de funciones son a menudo responsables de una gran parte de la sobrecarga del tiempo de ejecución, por lo que deshabilitar la mitigación en esas funciones puede maximizar el beneficio de seguridad y minimizar el costo de rendimiento. aquí es un ejemplo de esto en uno de los códecs de medios. Estas funciones exentas deben revisarse manualmente en busca de errores para reducir el riesgo de deshabilitar la mitigación allí.
  • Optimizar la implementación de la mitigación para mejorar su desempeño. A menudo, esto implica modificar el compilador. Por ejemplo, nuestro equipo ha transmitido optimizaciones al Entero Desbordamiento Desinfectante y el Límites Desinfectante.
  • Ciertas mitigaciones, como la solidez incorporada del asignador Scudo contra las vulnerabilidades basadas en el montón, han parámetros ajustables que se puede modificar para mejorar el rendimiento.

La mayoría de estas mejoras implican cambios o contribuciones al proyecto LLVM. Al trabajar con LLVM ascendente, estas mejoras tienen un impacto y beneficio más allá de Android. Al mismo tiempo, Android se beneficia de las mejoras iniciales cuando otros miembros de la comunidad LLVM también realizan mejoras.

Implementación y soporte

Cuando se habilita una mitigación, hay más cosas que considerar que su beneficio de seguridad y costo de rendimiento, como el costo de implementación a corto plazo y soporte a largo plazo.

Consideraciones sobre la estabilidad de la implementación

Un tema importante es si una mitigación puede contener falsos positivos. Por ejemplo, si Bounds Sanitizer produce un error, definitivamente hay un acceso fuera de los límites (aunque podría no ser explotable). Pero el desinfectante de desbordamiento de enteros puede producir falsos positivos, ya que muchos desbordamientos de enteros son inofensivos o incluso perfectamente esperados y correctos.

Por tanto, es importante considerar el impacto de una mitigación en la estabilidad del sistema. Ya sea que un bloqueo se deba a un falso positivo o un problema de seguridad legítimo, aún perturba la experiencia del usuario y, por lo tanto, no es deseable. Esta es otra razón para considerar cuidadosamente qué componentes deben tener qué mitigaciones, ya que las fallas en algunos componentes son peores que en otros. Si una mitigación provoca una falla en un códec de medios, la reproducción de video del usuario se detendrá, pero si netd se bloquea durante una actualización, el teléfono podría estar bloqueado. Para una mitigación como Bounds Sanitizer, donde los falsos positivos no son un problema, aún necesitamos realizar pruebas exhaustivas para garantizar que el dispositivo permanezca estable. Los errores uno por uno, por ejemplo, pueden no bloquearse durante el funcionamiento normal, pero Bounds Sanitizer interrumpiría la ejecución y provocaría inestabilidad.

Otra consideración es si es posible enumerar todo lo que podría romper una mitigación. Por ejemplo, no es fácil contener el riesgo de Integer Overflow Sanitizer sin pruebas exhaustivas, ya que es difícil determinar qué desbordamientos son intencionales / benignos (y por lo tanto deberían permitirse) y cuáles podrían generar vulnerabilidades.

Apoyo

Debemos considerar no solo los problemas causados ​​por la implementación de mitigaciones, sino también cómo respaldarlas a largo plazo. Esto incluye el tiempo del desarrollador para integrar una mitigación en los sistemas existentes, habilitarla y depurarla, implementarla en los dispositivos y admitirla después del lanzamiento. SELinux es un buen ejemplo de esto; Se necesita un esfuerzo significativo para escribir la política para un nuevo dispositivo, e incluso una vez que se habilita el modo de aplicación, la política debe ser compatible durante años a medida que se agregan o eliminan los cambios de código y la funcionalidad.

Intentamos hacer que las mitigaciones sean menos disruptivas y difundir la conciencia de cómo afectan a los desarrolladores. Esto se hace poniendo a disposición la documentación en source.android.com y mejorando los algoritmos existentes para reducir los falsos positivos. Facilitar la depuración de mitigaciones cuando algo sale mal reduce la carga de mantenimiento del desarrollador que puede acompañar a las mitigaciones. Por ejemplo, cuando a los desarrolladores les resultó difícil identificar errores de UBSan, habilitamos apoyo para UBSan Minimal Runtime de forma predeterminada en el sistema de compilación de Android. El tiempo de ejecución mínimo en sí fue el primero transmitido por otros en Google específicamente para este propósito. Cuando Integer Overflow Sanitizer bloquea un programa, eso agrega la siguiente pista al mensaje genérico de bloqueo de SIGABRT:

    Abort message: 'ubsan: sub-overflow'

Los desarrolladores que ven este mensaje saben que deben habilitar el modo de diagnóstico, que imprime detalles sobre el bloqueo:

    frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:2188:32: runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'size_t' (aka 'unsigned long')

De manera similar, SELinux ascendente proporciona una herramienta llamada audit2allow que puede usarse para sugerir reglas que permitan comportamientos bloqueados:

    adb logcat -d | audit2allow -p policy

    #============= rmt ==============
    allow rmt kmem_device:chr_file  read write ;

Una herramienta de depuración no necesita ser perfecta para ser útil; audit2allow no siempre sugiere las opciones correctas, pero para los desarrolladores sin un conocimiento detallado de SELinux, proporciona un sólido punto de partida.

Conclusión

Con cada lanzamiento de Android, nuestro equipo trabaja arduamente para equilibrar las mejoras de seguridad que benefician a todo el ecosistema con el rendimiento y la estabilidad, basándose en gran medida en los datos que están disponibles para nosotros. Esperamos que esto arroje algo de luz sobre los desafíos particulares involucrados y el proceso general que conduce a las mitigaciones introducidas en cada versión de Android.

Gracias a Jeff Vander Stoep por sus contribuciones a esta publicación de blog.



Enlace a la noticia original