Memoria de solo ejecución (XOM) para objetos binarios AArch64

Las secciones de código ejecutable para los objetos binarios del sistema AArch64 están marcadas de forma predeterminada de solo ejecución (no legible) como una mitigación más fortalecida contra el código justo a tiempo y reutilizar los ataques. Código que mezcle datos y código, y código que intencionalmente inspecciona estas secciones (sin volver a asignar primero los segmentos de la memoria como legibles) ya no funcionan. Apps con un SDK de destino de 10 (nivel de API 29 o versiones posteriores) se verán afectadas si la aplicación intenta leer secciones de código de bibliotecas de sistema habilitadas para memoria de solo ejecución (XOM) en la memoria sin antes y marca la sección como legible.

Para aprovechar al máximo esta mitigación, se requiere la compatibilidad con el hardware y el kernel como en los productos necesarios. Sin esta compatibilidad, la mitigación solo se podría aplicar de manera parcial. El El kernel común de Android 4.9 contiene los parches adecuados para brindar compatibilidad con esto en dispositivos ARMv8.2.

Implementación

Los objetos binarios AArch64 generados por el compilador suponen que el código y los datos entremezclados. Habilitar esta función no afecta negativamente el rendimiento de el dispositivo.

Para código que tiene que realizar una introspección intencional de la memoria en su ejecutables, se recomienda llamar a mprotect en el o segmentos de código que se deben inspeccionar para que sean legibles y, luego, para evitar la legibilidad cuando se complete la inspección.
Esta implementación genera lecturas en segmentos de memoria marcados como solo de ejecución para provocar una falla de segmentación (SEGFAULT). Esto puede ocurrir como resultado de un error, una vulnerabilidad, una mezcla de datos código (reducción literal) o introspección intencional de la memoria.

Impacto y compatibilidad de los dispositivos

Dispositivos con hardware o kernels anteriores (anteriores a la versión 4.9) sin el dispositivo es posible que los parches necesarios no sean totalmente compatibles con esta función o que no se beneficien de ella. Dispositivos sin compatibilidad con kernel puede no imponer el acceso de usuarios a memoria de solo ejecución Sin embargo, el código del kernel que verifica explícitamente si una página es legible podría igualmente aplicar esta propiedad, como process_vm_readv().

La marca CONFIG_ARM64_UAO del kernel debe configurarse en el kernel para asegúrate de que el kernel respete las páginas de userland marcadas como de solo ejecución. ARMv8 anterior o los dispositivos ARMv8.2 con anulación de acceso del usuario (UAO) inhabilitada, no pueden aprovechar esto y es posible que aún puedan leer páginas de solo ejecución con llamadas de sistema.

Cómo refactorizar código existente

El código que ha sido transferido de AArch32 puede contener datos entrelazados y código, lo que causa que surjan problemas. En muchos casos, solucionar estos problemas es tan simple como mover las constantes a una sección .data en el archivo de ensamblado.

Es posible que el ensamblaje escrito a mano deba refactorizarse para separar las agrupaciones locales constantes.

Ejemplos:

Los objetos binarios que genera el compilador Clang no deberían tener problemas con los datos. que se entremezclan en el código. Si el código generado por la colección del compilador GNU (GCC) se incluido (de una biblioteca estática), inspeccionarás el objeto binario de salida para asegurarse de que las constantes no se hayan agrupado en secciones de código.

Si es necesaria la introspección de código en secciones de código ejecutable, primero, llama a mprotect para marcar el código como legible. Luego, después de la operación se completó, llama nuevamente a mprotect para marcarlo como ilegible.

Habilitar XOM

La opción de solo ejecución está habilitada de forma predeterminada para todos los objetos binarios de 64 bits de la compilación en un sistema de archivos.

Inhabilitar XOM

Puedes inhabilitar el modo de solo ejecución a nivel de módulo, mediante un árbol de subdirectorios completo, o de forma global para una compilación completa.

XOM se puede inhabilitar para módulos individuales que no se pueden refactorizar o que deben leer su ejecutable, estableciendo LOCAL_XOM y las variables xom a false.

// Android.mk
LOCAL_XOM := false

// Android.bp
cc_binary { // or other module types
   ...
   xom: false,
}

Si la memoria de solo ejecución está inhabilitada en una biblioteca estática, se aplica el sistema de compilación esto a todos los módulos dependientes de esa biblioteca estática. Puedes anular usando xom: true,.

Para inhabilitar la memoria de solo ejecución en un subdirectorio en particular (por ejemplo, foo/bar/), pasa el valor a XOM_EXCLUDE_PATHS.

make -j XOM_EXCLUDE_PATHS=foo/bar

También puedes establecer el PRODUCT_XOM_EXCLUDE_PATHS variable en la configuración del producto.

Puedes inhabilitar los objetos binarios de solo ejecución globalmente si pasas ENABLE_XOM=false al comando make.

make -j ENABLE_XOM=false

Validación

No hay pruebas de CTS ni de verificación disponibles para pruebas de solo ejecución memoria. Puedes verificar los objetos binarios de forma manual con readelf y comprobando las marcas de segmento.