Extensão de inclusão de tag na memória ARM

A Arm v9 introduz a memória Arm Tagging Extension (MTE), uma implementação de hardware de memória marcada.

Em alto nível, a MTE marca cada alocação/desalocação de memória com metadados adicionais. Ela atribui uma tag a um local da memória, que pode ser associados a ponteiros que fazem referência a esse local da memória. No ambiente de execução, a CPU verifica se o ponteiro e as tags de metadados correspondem em cada carregamento e armazenamento.

No Android 12, o alocador de memória de heap do kernel e do espaço do usuário pode aumentar cada alocação com metadados. Isso ajuda a detectar bugs de estouro de buffer, que são a fonte mais comum de bugs de segurança de memória em das nossas bases de código.

Modos de operação da MTE

A MTE tem três modos de operação:

  • Modo síncrono (SYNC)
  • Modo assíncrono (ASYNC)
  • Modo assimétrico (ASYMM)

Modo síncrono (SYNC)

Esse modo é otimizado para mais precisão na detecção de bugs em relação ao desempenho e pode ser usada como uma ferramenta de detecção de bugs precisa, quando um overhead de desempenho maior é aceitáveis. Quando ativada, a MTE SYNC atua como uma mitigação de segurança. Em caso de incompatibilidade de tag, o processador cancela a execução imediatamente e encerra o processo com SIGSEGV (código SEGV_MTESERR) e informações completas sobre o acesso à memória e o endereço com falha.

Recomendamos usar esse modo durante os testes como uma alternativa HWASan/KASAN ou em produção quando o processo de destino representa uma vulnerabilidade de ataque menor. Além disso, quando o modo ASYNC indicou a presença de um um relatório de bug preciso pode ser obtido usando as APIs de ambiente de execução para alternar no modo SYNC.

Quando executado no modo SYNC, o alocador do Android registra os rastreamentos de pilha para todos os alocações e desalocações, e os usa para oferecer melhores relatórios de erros que incluem a explicação de um erro , como use-after-free ou estouro de buffer, e os rastreamentos de pilha do eventos de memória relevantes. Esses relatórios fornecem mais informações e facilitar o rastreamento e a correção de bugs.

Modo assíncrono (ASYNC)

Esse modo é otimizado para melhorar o desempenho em relação à precisão dos relatórios de bugs e pode ser usada como detecção de baixa sobrecarga para bugs de segurança de memória.
Em caso de incompatibilidade de tag, o processador continua a execução até que o entrada do kernel (por exemplo, uma chamada de sistema ou interrupção de timer), em que ele se encerra o processo com SIGSEGV (código SEGV_MTEAERR) sem gravar o endereço com falha ou o acesso à memória.
Recomendamos o uso desse modo em produção em bases de código bem testadas em que a densidade dos bugs de segurança de memória é baixa, o que é possível usando o modo SYNC durante o teste.

Modo assimétrico (ASYMM)

Um recurso adicional no Arm v8.7-A, o modo MTE assimétrica oferece verificação de leituras de memória e verificação assíncrona de gravações de memória, com desempenho semelhante ao do modo ASYNC. Na maioria das situações, é uma melhoria em relação ao modo ASYNC, e recomendamos usá-lo em vez de ASYNC sempre que estiver disponível.

Por esse motivo, nenhuma das APIs descritas abaixo menciona a API modo Em vez disso, o SO pode ser configurado para sempre usar o modo assimétrico quando A assíncrona é solicitada. Consulte a seção "Configuração específica da CPU nível de MTE preferido" para mais informações.

MTE no espaço do usuário

As seções a seguir descrevem como a MTE pode ser ativada para processos do sistema e apps. A MTE fica desativada por padrão, a menos que uma das opções abaixo seja definido para um determinado processo. Veja para quais componentes a MTE está ativada abaixo.

Ativar a MTE usando o sistema de build

Como uma propriedade de todo o processo, a MTE é controlada pela configuração do tempo de build dos o executável principal. As opções a seguir permitem alterar essa configuração para executáveis individuais ou para subdiretórios inteiros da árvore de origem. A será ignorada em bibliotecas ou em qualquer destino que não seja executável nem um teste.

1. Como ativar a MTE em Android.bp (exemplo) de um projeto específico:

Modo MTE Configuração
MTE assíncrona
  sanitize: {
  memtag_heap: true,
  }
MTE síncrona
  sanitize: {
  memtag_heap: true,
  diag: {
  memtag_heap: true,
  },
  }

ou em Android.mk:

Modo MTE Configuração
Asynchronous MTE LOCAL_SANITIZE := memtag_heap
Synchronous MTE LOCAL_SANITIZE := memtag_heap
LOCAL_SANITIZE_DIAG := memtag_heap

2. Como ativar a MTE em um subdiretório na árvore de origem usando um produto :

Modo MTE Incluir lista Excluir lista
assíncrono PRODUCT_MEMTAG_HEAP_ASYNC_INCLUDE_PATHS MEMTAG_HEAP_ASYNC_INCLUDE_PATHS PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS MEMTAG_HEAP_EXCLUDE_PATHS
sincronização PRODUCT_MEMTAG_HEAP_SYNC_INCLUDE_PATHS MEMTAG_HEAP_SYNC_INCLUDE_PATHS

ou

Modo MTE Configuração
MTE assíncrona MEMTAG_HEAP_ASYNC_INCLUDE_PATHS
MTE síncrona MEMTAG_HEAP_SYNC_INCLUDE_PATHS

ou especificando o caminho de exclusão de um executável:

Modo MTE Configuração
MTE assíncrona PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS MEMTAG_HEAP_EXCLUDE_PATHS
MTE síncrona

Exemplo, (uso semelhante ao de PRODUCT_CFI_INCLUDE_PATHS)

  PRODUCT_MEMTAG_HEAP_SYNC_INCLUDE_PATHS=vendor/$(vendor)
  PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS=vendor/$(vendor)/projectA \
                                    vendor/$(vendor)/projectB

Ativar a MTE usando propriedades do sistema

As configurações de compilação acima podem ser substituídas no ambiente de execução definindo o a seguir propriedade do sistema:

arm64.memtag.process.<basename> = (off|sync|async)

Em que basename é o nome de base do executável.

Por exemplo, para definir /system/bin/ping ou /data/local/tmp/ping para usar a MTE assíncrona, use adb shell setprop arm64.memtag.process.ping async.

Ativar a MTE usando uma variável de ambiente

Outra maneira de modificar a configuração do build é definir o ambiente variável: MEMTAG_OPTIONS=(off|sync|async) Se a variável de ambiente e a propriedade do sistema estiverem definidas, o tem prioridade.

Ativar a MTE para apps

Se não for especificado, a MTE será desativada por padrão, Para isso, os apps que quiserem usar a MTE poderão definir android:memtagMode nos termos da <application> ou na tag <process> AndroidManifest.xml.

. android:memtagMode=(off|default|sync|async)

Quando definido na tag <application>, o afeta todos os processos usados pelo app e pode ser substituído para processos individuais definindo <process>.

Para experimentação, compatibilidade alterações pode ser usada para definir o valor padrão do um atributo memtagMode de um app que não especificar um valor no manifesto (ou especificar default).
Elas podem ser encontradas em System > Advanced > Developer options > App Compatibility Changes no menu de configurações globais. Ambiente NATIVE_MEMTAG_ASYNC ou NATIVE_MEMTAG_SYNC ativa a MTE para um app específico.
Como alternativa, isso pode ser definido usando o método am da seguinte forma:

$ adb shell am compat enable NATIVE_MEMTAG_[A]SYNC my.app.name

Criar uma imagem do sistema MTE

Recomendamos ativar a MTE em todos os binários nativos durante o desenvolvimento e trazer à tona. Isso ajuda a detectar bugs de segurança de memória precocemente e oferece cobertura de usuários, se ativada em builds de teste.

Recomendamos ativar a MTE no modo síncrono em todos os binários nativos durante o desenvolvimento.

SANITIZE_TARGET=memtag_heap SANITIZE_TARGET_DIAG=memtag_heap m

Como acontece com qualquer variável no sistema de build, SANITIZE_TARGET pode ser usada como uma variável de ambiente ou uma configuração make (por exemplo, em um arquivo product.mk).
Isso ativa a MTE para todos os processos nativos, mas não para Apps (que são bifurcados de zygote64) para os quais a MTE pode ser ativada seguindo as instruções acima.

Configurar o nível de MTE preferencial específico da CPU

Em algumas CPUs, o desempenho da MTE nos modos ASYMM ou SYNC pode ser semelhante a a do ASYNC. Assim, vale a pena ativar verificações mais rigorosas nessas CPUs quando um modo de verificação menos rigoroso é solicitado, em a fim de aproveitar os benefícios de detecção de erros das verificações mais rigorosas sem as e desvantagens de desempenho.
Por padrão, os processos configurados para serem executados no modo ASYNC serão executados no ASYNC em todas as CPUs. Para configurar o kernel para executar esses processos no modo SYNC em CPUs específicas, o valor "sync" precisa ser gravado sysfs entrada /sys/devices/system/cpu/cpu<N>/mte_tcf_preferred na inicialização tempo de resposta. Isso pode ser feito com um script init. Por exemplo, para configurar CPUs de 0 a 1, para executar processos do modo ASYNC no modo SYNC e das CPUs 2 a 3 para usar a execução no modo ASYMM, o seguinte pode ser adicionado à cláusula init de um script init do fornecedor:

  write /sys/devices/system/cpu/cpu0/mte_tcf_preferred sync
  write /sys/devices/system/cpu/cpu1/mte_tcf_preferred sync
  write /sys/devices/system/cpu/cpu2/mte_tcf_preferred asymm
  write /sys/devices/system/cpu/cpu3/mte_tcf_preferred asymm

As tombstones dos processos do modo ASYNC em execução no modo SYNC conterão uma stack trace preciso do local do erro de memória. No entanto, eles não terão incluir um stack trace de alocação ou desalocação. Esses stack traces são apenas um disponível se o processo estiver configurado para ser executado no modo SYNC.

. int mallopt(M_THREAD_DISABLE_MEM_INIT, level)

em que level é 0 ou 1.
Desativa a inicialização de memória em Malloc e evita alteração de tags de memória a menos que seja necessário para correção.

int mallopt(M_MEMTAG_TUNING, level)

em que level é:

  • M_MEMTAG_TUNING_BUFFER_OVERFLOW
  • M_MEMTAG_TUNING_UAF

Seleciona a estratégia de alocação de tags.

  • A configuração padrão é M_MEMTAG_TUNING_BUFFER_OVERFLOW.
  • M_MEMTAG_TUNING_BUFFER_OVERFLOW - permite determinísticos detecção de bugs de estouro e subfluxo de buffer linear com a atribuição de tags distintas para alocações adjacentes. Esse modo tem uma chance um pouco menor de detectar bugs de uso após a liberação porque apenas metade dos valores de tag possíveis são disponíveis para cada local da memória. A MTE não consegue detectar overflow no mesmo grânulo de tags (bloco alinhado de 16 bytes) e pode perder valores transbordamento de dados mesmo nesse modo. Esse estouro não pode ser a causa da memória porque a memória dentro de um grânulo nunca é usada para múltiplas alocações.
  • M_MEMTAG_TUNING_UAF: permite tags aleatórias independentemente para uma probabilidade uniforme de aproximadamente 93% de detecção tanto espaciais (overflow de buffer) quanto temporal (use após free).

Além das APIs descritas acima, os usuários experientes podem querer esteja ciente do seguinte:

  • Configurar o registro de hardware do PSTATE.TCO pode suprima a verificação de tags (exemplo). Por exemplo, ao copiar um intervalo de memória com conteúdo de tag desconhecido ou resolver um gargalo de desempenho em um hot loop.
  • Ao usar M_HEAP_TAGGING_LEVEL_SYNC, o gerenciador de falhas do sistema fornece informações extras, como stack traces de alocação e desalocação. Essa funcionalidade requer acesso aos bits de tag e é ativada passando o SA_EXPOSE_TAGBITS ao definir o gerenciador de sinais. Qualquer programa que defina seu próprio indicador e delega falhas desconhecidas ao sistema, e é recomendado fazer o mesmo.

MTE no kernel

Para ativar o KASAN acelerado por MTE para o kernel, configure-o com CONFIG_KASAN=y (CONFIG_KASAN_HW_TAGS=y). Essas configurações são ativados por padrão em kernels de GKI, começando com Android 12-5.10.
Isso pode ser controlado no momento da inicialização usando os seguintes argumentos da linha de comando:

  • kasan=[on|off]: ativa ou desativa a KASAN (padrão: on).
  • kasan.mode=[sync|async] – escolha entre os modos síncrono e assíncrono (padrão: sync)
  • kasan.stacktrace=[on|off]: coletar ou não stack traces (padrão: on)
    • a coleta de stack trace também exige stack_depot_disable=off:
  • kasan.fault=[report|panic]: se apenas o relatório será mostrado, ou colocar o kernel em pânico (padrão: report). Independentemente disso, a verificação de tags é desativada depois do primeiro erro informado.
.

É altamente recomendável usar o modo SYNC durante a introdução, o desenvolvimento testes. Essa opção precisa ser ativada globalmente para todos os processos que usam a variável de ambiente ou o sistema de build. Neste modo, bugs são detectados logo no início do processo de desenvolvimento, a base de código é estabilizada mais rapidamente, custos de detecção de bugs mais tarde na produção é evitado.

É altamente recomendável usar o modo ASYNC na produção. Isso fornece uma baixa ferramenta de sobrecarga para detectar a presença de bugs de segurança de memória em um processo como além de mais defesa em profundidade. Quando um bug é detectado, o desenvolvedor pode aproveitar as APIs de tempo de execução para alternar para o modo SYNC e obter um rastreamento de pilha preciso de um conjunto de amostra de usuários.

Recomendamos configurar o nível de MTE preferencial específico da CPU para o SoC. O modo Asymm normalmente tem as mesmas características de desempenho que o ASYNC, e quase sempre é a melhor opção. Núcleos em ordem pequenos geralmente mostram desempenho nos três modos e pode ser configurado para preferir SYNC.

Os desenvolvedores precisam conferir se há falhas /data/tombstones, logcat ou monitorando o fornecedor DropboxManager em busca de bugs do usuário final. Para mais informações sobre depuração de código nativo do Android, consulte as informações aqui.

Componentes de plataforma com MTE ativado

No Android 12, vários componentes essenciais de segurança do sistema usam a MTE ASYNC para detectar falhas de usuários finais e atuar como uma camada adicional de defesa em profundidade. Esses componentes são:

  • Daemons e utilitários de rede (com exceção dos netd)
  • Bluetooth, SecureElement, HALs de NFC e apps do sistema
  • Daemon statsd
  • system_server
  • zygote64 (para permitir que os apps ativem o uso da MTE)

Esses segmentos foram selecionados com base nos seguintes critérios:

  • Processo privilegiado (definido como um processo que tem acesso a algo que o domínio do SELinux unprivileged_app não)
  • Processa entradas não confiáveis (Regra de dois)
  • Lentidão no desempenho aceitável (a lentidão não cria visibilidade para o usuário latência)

Incentivamos os fornecedores a ativar a MTE na produção de mais componentes seguindo os critérios mencionados acima. Durante o desenvolvimento, recomendamos testar esses componentes usando o modo SYNC, para detectar bugs facilmente corrigidos e avaliar a O impacto do ASYNC em seu desempenho.
No futuro, o Android planeja expandir a lista de componentes do sistema que a MTE está ativado, orientado pelas características de desempenho dos próximos projetos de hardware.