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 oSA_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
:
- a coleta de stack trace também exige
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.
Uso recomendado
É 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.