Memory Tagging Extension (MTE)

Reading time: 5 minutes

tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Informações Básicas

Memory Tagging Extension (MTE) é projetado para aumentar a confiabilidade e segurança do software, detectando e prevenindo erros relacionados à memória, como estouros de buffer e vulnerabilidades de uso após a liberação. O MTE, como parte da arquitetura ARM, fornece um mecanismo para anexar uma pequena tag a cada alocação de memória e uma tag correspondente a cada ponteiro que referencia essa memória. Essa abordagem permite a detecção de acessos ilegais à memória em tempo de execução, reduzindo significativamente o risco de explorar tais vulnerabilidades para executar código arbitrário.

Como Funciona a Memory Tagging Extension

O MTE opera dividindo a memória em pequenos blocos de tamanho fixo, com cada bloco atribuído a uma tag, tipicamente de alguns bits de tamanho.

Quando um ponteiro é criado para apontar para essa memória, ele recebe a mesma tag. Essa tag é armazenada nos bits não utilizados de um ponteiro de memória, vinculando efetivamente o ponteiro ao seu bloco de memória correspondente.

https://www.youtube.com/watch?v=UwMt0e_dC_Q

Quando um programa acessa a memória através de um ponteiro, o hardware do MTE verifica se a tag do ponteiro corresponde à tag do bloco de memória. Se as tags não corresponderem, isso indica um acesso ilegal à memória.

Tags de Ponteiro MTE

As tags dentro de um ponteiro são armazenadas em 4 bits dentro do byte superior:

https://www.youtube.com/watch?v=UwMt0e_dC_Q

Portanto, isso permite até 16 valores de tag diferentes.

Tags de Memória MTE

Cada 16B de memória física tem uma tag de memória correspondente.

As tags de memória são armazenadas em uma região de RAM dedicada (não acessível para uso normal). Tendo tags de 4 bits para cada 16B de tags de memória, até 3% da RAM.

A ARM introduz as seguintes instruções para manipular essas tags na memória RAM dedicada:

STG [<Xn/SP>], #<simm>    Store Allocation (memory) Tag
LDG <Xt>, [<Xn/SP>]       Load Allocatoin (memory) Tag
IRG <Xd/SP>, <Xn/SP>      Insert Random [pointer] Tag
...

Verificando Modos

Sync

A CPU verifica as tags durante a execução da instrução, se houver uma incompatibilidade, ela gera uma exceção.
Este é o mais lento e mais seguro.

Async

A CPU verifica as tags assíncronamente, e quando uma incompatibilidade é encontrada, ela define um bit de exceção em um dos registradores do sistema. É mais rápido do que o anterior, mas é incapaz de apontar a instrução exata que causou a incompatibilidade e não gera a exceção imediatamente, dando algum tempo ao atacante para completar seu ataque.

Mixed

???

Exemplos de Implementação e Detecção

Chamado de KASAN baseado em Tag de Hardware, KASAN baseado em MTE ou MTE em kernel.
Os alocadores do kernel (como kmalloc) chamarão este módulo que preparará a tag para usar (aleatoriamente) anexá-la ao espaço do kernel alocado e ao ponteiro retornado.

Note que ele marcará apenas grânulos de memória suficientes (16B cada) para o tamanho solicitado. Portanto, se o tamanho solicitado foi 35 e um slab de 60B foi dado, ele marcará os primeiros 16*3 = 48B com esta tag e o restante será marcado com uma chamada de tag inválida (0xE).

A tag 0xF é o ponteiro que combina todos. Uma memória com este ponteiro permite que qualquer tag seja usada para acessar sua memória (sem incompatibilidades). Isso poderia impedir que o MET detectasse um ataque se essas tags estiverem sendo usadas na memória atacada.

Portanto, existem apenas 14 valores que podem ser usados para gerar tags, pois 0xE e 0xF são reservados, dando uma probabilidade de reutilização de tags de 1/17 -> cerca de 7%.

Se o kernel acessar o grânulo de tag inválida, a incompatibilidade será detectada. Se acessar outro local de memória, se a memória tiver uma tag diferente (ou a tag inválida), a incompatibilidade será detectada. Se o atacante tiver sorte e a memória estiver usando a mesma tag, não será detectada. As chances são em torno de 7%.

Outro bug ocorre no último grânulo da memória alocada. Se a aplicação solicitou 35B, foi dado o grânulo de 32 a 48. Portanto, os bytes de 36 a 47 estão usando a mesma tag mas não foram solicitados. Se o atacante acessar esses bytes extras, isso não é detectado.

Quando kfree() é executado, a memória é retagged com a tag de memória inválida, então em um use-after-free, quando a memória é acessada novamente, a incompatibilidade é detectada.

No entanto, em um use-after-free, se o mesmo chunk for realocado novamente com a MESMA tag que anteriormente, um atacante poderá usar esse acesso e isso não será detectado (cerca de 7% de chance).

Além disso, apenas slab e page_alloc usam memória marcada, mas no futuro isso também será usado em vmalloc, stack e globals (no momento do vídeo, esses ainda podem ser abusados).

Quando uma incompatibilidade é detectada, o kernel irá panic para evitar mais exploração e tentativas do exploit (MTE não tem falsos positivos).

Referências

tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks