Memória somente execução (XOM) para binários AArch64

As seções de código executável para binários do sistema AArch64 são, por padrão, marcadas como somente execução (não legível) como uma mitigação de proteção contra ataques de reutilização de código just-in-time. O código que mistura dados e código e o código que inspeciona propositalmente essas seções (sem primeiro remapear os segmentos de memória como legíveis) não funcionam mais. Aplicativos com SDK de destino 10 (nível de API 29 ou superior) serão afetados se o aplicativo tentar ler seções de código de bibliotecas de sistema habilitadas para memória somente execução (XOM) na memória sem primeiro marcar a seção como legível.

Para aproveitar totalmente essa mitigação, é necessário suporte de hardware e de kernel. Sem este apoio, a mitigação poderá ser apenas parcialmente aplicada. O kernel comum do Android 4.9 contém os patches apropriados para fornecer suporte completo para isso em dispositivos ARMv8.2.

Implementação

Os binários AArch64 gerados pelo compilador assumem que o código e os dados não estão misturados. A ativação deste recurso não afeta negativamente o desempenho do dispositivo.

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

Suporte e impacto do dispositivo

Dispositivos com hardware anterior ou kernels anteriores (inferiores a 4.9) sem os patches necessários podem não oferecer suporte total ou se beneficiar desse recurso. Dispositivos sem suporte de kernel podem não impor acessos de 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 impor essa propriedade, como process_vm_readv() .

O sinalizador do kernel CONFIG_ARM64_UAO deve ser definido no kernel para garantir que o kernel respeite as páginas do usuário marcadas como somente execução. Dispositivos ARMv8 anteriores, ou dispositivos ARMv8.2 com User Access Override (UAO) desativado, podem não se beneficiar totalmente disso e ainda podem ser capazes de ler páginas somente de execução usando syscalls.

Refatorando código existente

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

A montagem manuscrita pode precisar ser refatorada para separar constantes agrupadas localmente.

Exemplos:

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

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

Possibilitando

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

Desativando

Você pode desabilitar somente execução em nível de módulo, por uma árvore de subdiretórios inteira ou globalmente para uma compilação inteira.

O XOM pode ser desabilitado para módulos individuais que não podem ser refatorados ou que precisam ler seu código executável, definindo as variáveis LOCAL_XOM e xom como 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 desabilitada em uma biblioteca estática, o sistema de compilação aplicará isso a todos os módulos dependentes dessa biblioteca estática. Você pode substituir isso usando xom: true, .

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

make -j XOM_EXCLUDE_PATHS=foo/bar

Como alternativa, você pode definir a variável PRODUCT_XOM_EXCLUDE_PATHS na configuração do produto.

Você pode desabilitar binários somente de execução globalmente passando ENABLE_XOM=false para seu comando make .

make -j ENABLE_XOM=false

Validação

Não há CTS ou testes de verificação disponíveis para memória somente de execução. Você pode verificar manualmente os binários usando readelf e verificando os sinalizadores de segmento.