Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.
Se usó la API de Cloud Translation para traducir esta página.
Switch to English

Integridad del flujo de control

A partir de 2016, alrededor del 86% de todas las vulnerabilidades en Android están relacionadas con la seguridad de la memoria. La mayoría de las vulnerabilidades son explotadas por atacantes que cambian el flujo de control normal de una aplicación para realizar actividades maliciosas arbitrarias con todos los privilegios de la aplicación explotada. La integridad del flujo de control (CFI) es un mecanismo de seguridad que no permite cambios en el gráfico de flujo de control original de un binario compilado, lo que dificulta mucho la realización de tales ataques.

En Android 8.1, habilitamos la implementación de CFI de LLVM en la pila de medios. En Android 9, habilitamos CFI en más componentes y también en el kernel. La CFI del sistema está activada de forma predeterminada, pero debe habilitar la CFI del núcleo.

CFI de LLVM requiere compilar con Link-Time Optimization (LTO) . LTO conserva la representación de código de bits LLVM de los archivos objeto hasta el momento del enlace, lo que permite al compilador razonar mejor sobre las optimizaciones que se pueden realizar. Habilitar LTO reduce el tamaño del binario final y mejora el rendimiento, pero aumenta el tiempo de compilación. En las pruebas en Android, la combinación de LTO y CFI da como resultado una sobrecarga insignificante en el tamaño y el rendimiento del código; en unos pocos casos ambos mejoraron.

Para obtener más detalles técnicos sobre CFI y cómo se manejan otras verificaciones de control de avance, consulte la documentación de diseño de LLVM .

Ejemplos y fuente

El compilador proporciona CFI y agrega instrumentación al binario durante el tiempo de compilación. Admitimos CFI en la cadena de herramientas de Clang y el sistema de compilación de Android en AOSP.

CFI está habilitado de forma predeterminada para los dispositivos Arm64 para el conjunto de componentes en /platform/build/target/product/cfi-common.mk . También está habilitado directamente en un conjunto de archivos makefiles / blueprint de componentes multimedia, como /platform/frameworks/av/media/libmedia/Android.bp y /platform/frameworks/av/cmds/stagefright/Android.mk .

Implementación del sistema CFI

CFI está habilitado de forma predeterminada si usa Clang y el sistema de compilación de Android. Como CFI ayuda a mantener seguros a los usuarios de Android, no debe desactivarlo.

De hecho, le recomendamos encarecidamente que habilite CFI para componentes adicionales. Los candidatos ideales son el código nativo privilegiado o el código nativo que procesa la entrada de usuarios que no son de confianza. Si está utilizando clang y el sistema de compilación de Android, puede habilitar CFI en nuevos componentes agregando algunas líneas a sus archivos MAKE o blueprint.

Apoyar CFI en archivos MAKE

Para habilitar CFI en un archivo make, como /platform/frameworks/av/cmds/stagefright/Android.mk , agregue:

LOCAL_SANITIZE := cfi
# Optional features
LOCAL_SANITIZE_DIAG := cfi
LOCAL_SANITIZE_BLACKLIST := cfi_blacklist.txt
  • LOCAL_SANITIZE especifica CFI como desinfectante durante la construcción.
  • LOCAL_SANITIZE_DIAG activa el modo de diagnóstico para CFI. El modo de diagnóstico imprime información de depuración adicional en logcat durante las fallas, lo cual es útil al desarrollar y probar sus compilaciones. Sin embargo, asegúrese de eliminar el modo de diagnóstico en las compilaciones de producciones.
  • LOCAL_SANITIZE_BLACKLIST permite que los componentes deshabiliten selectivamente la instrumentación CFI para funciones individuales o archivos fuente. Puede usar una lista negra como último recurso para solucionar cualquier problema que enfrenta el usuario que de otro modo podría existir. Para obtener más detalles, consulte Desactivación de CFI .

Apoyar CFI en archivos de planos

Para habilitar CFI en un archivo de plano, como /platform/frameworks/av/media/libmedia/Android.bp , agregue:

   sanitize: {
        cfi: true,
        diag: {
            cfi: true,
        },
        blacklist: "cfi_blacklist.txt",
    },

Solución de problemas

Si habilita CFI en componentes nuevos, es posible que tenga algunos problemas con errores de desajuste del tipo de función y errores de desajuste del tipo de código de ensamblaje .

Los errores de discrepancia de tipo de función se producen porque CFI restringe las llamadas indirectas para que solo salten a funciones que tienen el mismo tipo dinámico que el tipo estático utilizado en la llamada. CFI restringe las llamadas a funciones miembro virtuales y no virtuales para que solo salten a objetos que son una clase derivada del tipo estático del objeto utilizado para realizar la llamada. Esto significa que, cuando tiene un código que viola cualquiera de estos supuestos, la instrumentación que agrega CFI se abortará. Por ejemplo, el seguimiento de la pila muestra un SIGABRT y logcat contiene una línea sobre la integridad del flujo de control que encuentra una discrepancia.

Para solucionar esto, asegúrese de que la función llamada tenga el mismo tipo que se declaró estáticamente. Aquí hay dos CL de ejemplo:

Otro posible problema es intentar habilitar CFI en un código que contiene llamadas indirectas al ensamblaje. Debido a que el código ensamblador no se escribe, esto da como resultado una falta de coincidencia de tipos.

Para solucionar este problema, cree envoltorios de código nativo para cada llamada de ensamblado y asigne a los envoltorios la misma firma de función que el puntero de llamada. El contenedor puede llamar directamente al código ensamblador. Como las ramas directas no están instrumentadas por CFI (no se pueden reasignar en tiempo de ejecución y, por lo tanto, no representan un riesgo de seguridad), esto solucionará el problema.

Si hay demasiadas funciones de ensamblaje y no todas pueden arreglarse, también puede incluir en la lista negra todas las funciones que contienen llamadas indirectas a ensamblado. Esto no se recomienda ya que deshabilita las comprobaciones de CFI en estas funciones, lo que abre la superficie de ataque.

Deshabilitar CFI

No observamos ninguna sobrecarga de rendimiento, por lo que no debería necesitar deshabilitar CFI. Sin embargo, si hay un impacto de cara al usuario, puede deshabilitar selectivamente CFI para funciones individuales o archivos fuente proporcionando un archivo de lista negra de desinfectante en el momento de la compilación. La lista negra indica al compilador que desactive la instrumentación CFI en ubicaciones específicas.

El sistema de compilación de Android proporciona soporte para listas negras por componente (lo que le permite elegir archivos de origen o funciones individuales que no recibirán instrumentación CFI) tanto para Make como para Soong. Para obtener más detalles sobre el formato de un archivo de lista negra, consulte los documentos de Clang anteriores .

Validación

Actualmente, no hay una prueba CTS específica para CFI. En su lugar, asegúrese de que las pruebas CTS pasen con o sin CFI habilitado para verificar que CFI no esté afectando el dispositivo.