Memória somente de execução (XOM, na sigla em inglês) para binários AArch64

As seções de código executáveis dos binários do sistema AArch64 são marcadas por padrão somente execução (não legível) como uma mitigação de aumento da proteção contra o código just-in-time reutilização de ataques. Códigos que combinam dados e código e códigos que intencionalmente inspeciona essas seções (sem primeiro remapear os segmentos de memória como legíveis) não funcionam mais. Apps com um SDK desejado de 10 (nível 29 da API ou mais recente) serão afetadas se o app tentar ler seções de código com memória somente de execução (XOM, na sigla em inglês) com as bibliotecas do sistema ativadas na memória marcando a seção como legível.

Para se beneficiar plenamente dessa mitigação, o suporte a hardware e kernel é obrigatórios. Sem esse suporte, a mitigação pode ser aplicada apenas parcialmente. A O kernel comum do Android 4.9 contém os patches apropriados para fornecer suporte para isso em dispositivos ARMv8.2.

Implementação

Os binários AArch64 gerados pelo compilador presumem que o código e os dados não são misturadas. A ativação desse recurso não afeta negativamente o desempenho da o dispositivo.

Para um código que precisa realizar introspecção intencional da memória em seu segmentos executáveis, é aconselhável chamar mprotect no segmentos de código que exigem inspeção para serem legíveis, então e remover a legibilidade quando a inspeção for concluída.
Essa implementação faz com que leituras em segmentos de memória marcados como somente execução para resultar em uma falha de segmentação (SEGFAULT). Isso pode ocorrer como resultado de um bug, vulnerabilidade, dados misturados com (pooling literal) ou introspecção intencional da memória.

Compatibilidade e impacto do dispositivo

Dispositivos com hardware anterior ou kernels anteriores (anteriores à versão 4.9) sem a os patches necessários talvez não ofereçam suporte ou se beneficiem totalmente desse recurso. Dispositivos sem suporte ao kernel pode não impor acesso do usuário à memória somente de execução, No entanto, o código do kernel que verifica explicitamente se uma página é legível ainda pode aplicar essa propriedade, como process_vm_readv().

A flag CONFIG_ARM64_UAO precisa ser definida no kernel para certifique-se de que o kernel respeite as páginas do userland marcadas como somente execução. ARMv8 anterior ou ARMv8.2 com a Substituição de acesso do usuário (UAO) desativada, não podem aproveitar esse recurso e ler páginas somente de execução usando chamadas do sistema.

Refatorar um código existente

O código que foi transferido do AArch32 pode conter dados misturados e no código, causando problemas. Em muitos casos, corrigir esses problemas é tão simples como mover as constantes para uma seção .data no arquivo assembly.

A montagem escrita à mão pode precisar ser refatorada para separar os conjuntos locais constantes.

Exemplos:

Os binários gerados pelo compilador Clang não devem ter problemas com dados misturados no código. Se o código gerado da coleção do compilador GNU (GCC) for incluído (de uma biblioteca estática), inspecione o binário de saída para garantir que as constantes não sejam agrupadas em seções de código.

Se a introspecção do código for necessária em seções de código executável, chame mprotect para marcar o código como legível. Depois que a operação for concluída, chame mprotect novamente para marcá-la como ilegível.

Ativar XOM

Somente execução é ativado por padrão para todos os binários de 64 bits no build sistema.

Desativar XOM

Você pode desativar somente execução em um nível de módulo, por uma árvore de subdiretório inteira ou globalmente para um build inteiro.

O XOM pode ser desativado para módulos individuais que não podem ser refatorados ou que precisam ler código executável, definindo a propriedade LOCAL_XOM e variáveis xom para false.

// Android.mk
LOCAL_XOM := false

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

Se a memória somente de execução estiver desativada em uma biblioteca estática, o sistema de build aplicará para todos os módulos dependentes dessa biblioteca estática. É possível modificar isso usando xom: true,.

Para desativar a memória somente de execução em um subdiretório específico (por exemplo, foo/bar/), transmita o valor para XOM_EXCLUDE_PATHS.

make -j XOM_EXCLUDE_PATHS=foo/bar

Como alternativa, defina o PRODUCT_XOM_EXCLUDE_PATHS na configuração do produto.

É possível desativar os binários somente de execução globalmente transmitindo ENABLE_XOM=false ao comando make.

make -j ENABLE_XOM=false

Validação

Não há testes de CTS ou de verificação disponíveis somente para execução memória. Verifique os binários manualmente usando readelf e checando as sinalizações de segmento.