Integridad del flujo de control

Hasta 2016, alrededor del 86% de todas las vulnerabilidades de Android son de seguridad de la memoria. relacionados. La mayoría de las vulnerabilidades son aprovechadas por atacantes que cambian la normalidad de control de una aplicación para realizar actividades maliciosas arbitrarias todos los privilegios de la aplicación explotada. Flujo de control integridad (CFI) es un mecanismo de seguridad que no permite cambios en la grafo de flujo de control original de un objeto binario compilado, lo que dificulta considerablemente de realizar estos ataques.

En Android 8.1, habilitamos la implementación de CFI por parte de LLVM en la pila de medios. En En Android 9, habilitamos la CFI en más componentes y también en el kernel. El CFI del sistema es de forma predeterminada, pero debes habilitar la CFI del kernel.

La CFI de LLVM requiere compilar con Optimización del tiempo de vinculación (LTO). LTO conserva la representación del código de bits de LLVM de los archivos de objetos hasta tiempo de vinculación, que le permite al compilador entender mejor las optimizaciones se puede llevar a cabo el proceso. Habilitar LTO reduce el tamaño del objeto binario final y mejora rendimiento, pero aumenta el tiempo de compilación. En las pruebas en Android, la combinación de LTO y CFI genera una sobrecarga insignificante en el tamaño y el rendimiento del código. en una mejoraron algunos casos.

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

Ejemplos y fuente

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

La CFI está habilitada de forma predeterminada en dispositivos Arm64 para el conjunto de componentes en /platform/build/target/product/cfi-common.mk También se habilita directamente en un conjunto de componentes multimedia archivos makefile/plano como /platform/frameworks/av/media/libmedia/Android.bp y /platform/frameworks/av/cmds/stagefright/Android.mk.

Implementar el CFI del sistema

La CFI está habilitada de forma predeterminada si usas Clang y el sistema de compilación de Android. Debido a que la CFI ayuda a mantener seguros a los usuarios de Android, no debes inhabilitarla.

De hecho, te recomendamos que habilites la CFI para componentes adicionales. Los candidatos ideales son el código nativo con privilegios o el código nativo que procesa de usuarios que no son de confianza. Si usas Clang y el sistema de compilación de Android, Puedes habilitar la CFI en nuevos componentes agregando algunas líneas a tus archivos makefile o archivos de planos.

Compatibilidad con CFI en archivos makefile

Para habilitar la CFI en un archivo make, como /platform/frameworks/av/cmds/stagefright/Android.mk, haz lo siguiente: agregar:

LOCAL_SANITIZE := cfi
# Optional features
LOCAL_SANITIZE_DIAG := cfi
LOCAL_SANITIZE_BLACKLIST := cfi_blacklist.txt

  • LOCAL_SANITIZE especifica la CFI como limpiador durante la compilar.
  • 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 falla, lo cual es útil mientras desarrollas y pruebas tus compilaciones. Marca asegúrate de quitar el modo de diagnóstico en las compilaciones de producción.
  • LOCAL_SANITIZE_BLACKLIST permite que los componentes Inhabilitar la instrumentación de CFI para funciones individuales o archivos de origen. Tú puedes usar una lista negra como último recurso para solucionar cualquier problema que enfrenta el usuario podrían existir de otro modo. Para obtener más detalles, consulta Inhabilita la CFI.

Compatibilidad con CFI en archivos de planos

Para habilitar la CFI en un archivo de plano, como /platform/frameworks/av/media/libmedia/Android.bp, haz lo siguiente: agregar:

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

Solución de problemas

Si habilitas la CFI en componentes nuevos, es posible que tengas algunos problemas con Errores de discrepancia de tipos de funciones y Errores de discrepancia de tipos de códigos de ensamblado errores.

Se producen errores de no coincidencia de tipo de función porque la CFI restringe las llamadas indirectas solo a saltar a funciones que tienen el mismo tipo dinámico que el tipo estático usado en la llamada. La CFI restringe las llamadas a funciones de miembros virtuales y no virtuales para solo saltar a objetos que son una clase derivada del tipo estático del objeto que se usa para realizar la llamada. Esto significa que, cuando tienes un código que infringe cualquiera de la instrumentación que agregue la CFI se anulará. Por ejemplo, el seguimiento de pila muestra un SIGABRT y logcat contiene una línea sobre el flujo de control de integridad y encontrar una discrepancia.

Para solucionar esto, asegúrate de que la función a la que se llamó tenga el mismo tipo que declarada de forma estática. Aquí hay dos CL de ejemplo:

Otro posible problema es intentar habilitar la CFI en un código que contiene entradas llamadas a ensamblaje. Como el código de ensamblado no está escrito, el resultado será un tipo no coincide.

Para solucionar esto, crea wrappers de código nativo para cada llamada de ensamblado y asigna al contiene la misma firma de función que el elemento de llamada. Luego, el wrapper llamar directamente al código de ensamblado. Debido a que las ramas directas no son instrumentadas CFI (no se pueden repuntar en el tiempo de ejecución, por lo que no representan un riesgo de seguridad) esto solucionará el problema.

Si hay demasiadas funciones de ensamblaje y no se pueden reparar todas, puedes también incluye en una lista negra todas las funciones que contengan llamadas indirectas a ensamblaje. Este es no se recomienda, ya que inhabilita las verificaciones de CFI en estas funciones y, por lo tanto, abre superficie de ataque.

Inhabilita la CFI

No observamos ninguna sobrecarga de rendimiento, por lo que no debería ser necesario inhabilitar es el CFI. Sin embargo, si esto afecta al usuario, puedes inhabilitar CFI de forma selectiva. para funciones individuales o archivos de origen, proporcionando un archivo de lista negra de limpieza durante el tiempo de compilación. La lista negra le indica al compilador que inhabilite la CFI para la instrumentación en ubicaciones específicas.

El sistema de compilación de Android brinda compatibilidad con listas negras por componente (lo que permite que elijas archivos fuente o funciones individuales que no recibirán CFI para Make y Soong. Para obtener más información sobre el formato de un de la lista negra, consulta la sección upstream Documentos de Clang.

Validación

Actualmente, no hay una prueba de CTS específica para CFI. En cambio, asegúrate de que Las pruebas del CTS se aprueban con o sin la CFI habilitada para verificar que esta no tenga un impacto en ella el dispositivo.