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

Las secciones de código ejecutable para los binarios del sistema AArch64 están marcadas de forma predeterminada como de solo ejecución (no legibles) como una mitigación de refuerzo contra ataques de reutilización de código justo a tiempo. El código que mezcla datos y código y el código que inspecciona intencionadamente estas secciones (sin reasignar primero los segmentos de memoria como legibles) ya no funcionan. Las aplicaciones con un SDK de destino de 10 (nivel de API 29 o superior) se ven afectadas si la aplicación intenta leer secciones de código de bibliotecas del sistema habilitadas para memoria de solo ejecución (XOM) en la memoria sin marcar primero la sección como legible.

Para beneficiarse plenamente de esta mitigación, se requiere soporte tanto de hardware como de kernel. Sin este apoyo, la mitigación podría aplicarse sólo parcialmente. El kernel común de Android 4.9 contiene los parches apropiados para brindar soporte completo para esto en dispositivos ARMv8.2.

Implementación

Los archivos binarios AArch64 generados por el compilador suponen que el código y los datos no están mezclados. Habilitar esta función no afecta negativamente el rendimiento del dispositivo.

Para el código que tiene que realizar una introspección de memoria intencional en sus segmentos ejecutables, es recomendable llamar mprotect en los segmentos de código que requieren inspección para permitir que sean legibles y luego eliminar la legibilidad cuando se complete la inspección.
Esta implementación hace que las lecturas en segmentos de memoria marcados como de solo ejecución resulten en un error de segmentación ( SEGFAULT ). Esto puede ocurrir como resultado de un error, una vulnerabilidad, datos mezclados con código (agrupación literal) o una introspección de memoria intencional.

Soporte e impacto del dispositivo

Es posible que los dispositivos con hardware anterior o kernels anteriores (inferiores a 4.9) sin los parches necesarios no admitan o no se beneficien completamente de esta función. Es posible que los dispositivos sin soporte de kernel no exijan el acceso de los usuarios a la memoria de solo ejecución; sin embargo, el código del kernel que verifica explícitamente si una página es legible aún puede exigir esta propiedad, como process_vm_readv() .

El indicador del kernel CONFIG_ARM64_UAO debe configurarse en el kernel para garantizar que el kernel respete las páginas del área de usuario marcadas como de solo ejecución. Es posible que los dispositivos ARMv8 anteriores o los dispositivos ARMv8.2 con la Anulación de acceso de usuario (UAO) deshabilitada no se beneficien completamente de esto y aún puedan leer páginas de solo ejecución usando llamadas al sistema.

Refactorizando código existente

El código que se ha portado desde AArch32 puede contener datos y código entremezclados, lo que provoca que surjan problemas. En muchos casos, solucionar estos problemas es tan simple como mover las constantes a una sección .data en el archivo ensamblador.

Es posible que sea necesario refactorizar el ensamblaje escrito a mano para separar las constantes agrupadas localmente.

Ejemplos:

Los binarios generados por el compilador Clang no deberían tener problemas con la mezcla de datos en el código. Si se incluye código generado por la colección de compiladores GNU (GCC) (de una biblioteca estática), inspeccione el binario de salida para asegurarse de que las constantes no se hayan agrupado en secciones de código.

Si es necesaria la introspección del código en las secciones del código ejecutable, primero llame a mprotect para marcar el código como legible. Luego, una vez completada la operación, llame mprotect nuevamente para marcarlo como ilegible.

Habilitando

La opción Solo ejecución está habilitada de forma predeterminada para todos los binarios de 64 bits en el sistema de compilación.

Deshabilitar

Puede deshabilitar la ejecución solo a nivel de módulo, en un árbol de subdirectorios completo o globalmente para una compilación completa.

XOM se puede deshabilitar para módulos individuales que no se pueden refactorizar o que necesitan leer su código ejecutable, configurando las variables LOCAL_XOM y xom en false .

// Android.mk
LOCAL_XOM := false

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

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

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

make -j XOM_EXCLUDE_PATHS=foo/bar

Alternativamente, puede configurar la variable PRODUCT_XOM_EXCLUDE_PATHS en la configuración de su producto.

Puede deshabilitar los binarios de solo ejecución globalmente pasando ENABLE_XOM=false a su comando make .

make -j ENABLE_XOM=false

Validación

No hay CTS ni pruebas de verificación disponibles para la memoria de solo ejecución. Puede verificar manualmente los archivos binarios usando readelf y verificando las banderas del segmento.