Informazioni sui report MTE

Gli arresti anomali di SIGSEGV con codice 9 (SEGV_MTESERR) o codice 8 (SEGV_MTEAERR) sono errori di tagging della memoria. L'estensione di tagging della memoria (MTE) è una Funzionalità Armv9 supportata in Android 12 e versioni successive. MTE è un'implementazione hardware la memoria. Fornisce una protezione della memoria granulare per il rilevamento e la mitigazione di bug di sicurezza della memoria.

In C/C++, un puntatore restituito da una chiamata a Malloc() o all'operatore new() o a funzioni simili può essere utilizzato solo per accedere alla memoria entro i limiti di tale allocazione e solo mentre l'allocazione sia attiva (non libera o eliminata). La funzionalità MTE viene utilizzata in Android per rilevare violazioni delle questa regola, indicata nei report sugli arresti anomali come "Buffer Overflow"/"Buffer Underflow" e "Use After Free" che le applicazioni presentino problemi di prestazioni.

MTE ha due modalità: sincrona (o "sincrona") e asincrona (o "asincrona"). Il primo esegue più spesso ma fornisce una diagnostica più accurata. La seconda è più veloce, ma può fornire approssimati. Li tratteremo entrambi separatamente, poiché la diagnostica è leggermente diversa.

Modalità sincrona MTE

Nella modalità sincrona ("sincronizzazione") di MTE, SIGSEGV si arresta in modo anomalo con codice 9 (SEGV_MTESERR).

pid: 13935, tid: 13935, name: sanitizer-statu  >>> sanitizer-status <<<
uid: 0
tagged_addr_ctrl: 000000000007fff3
signal 11 (SIGSEGV), code 9 (SEGV_MTESERR), fault addr 0x800007ae92853a0
Cause: [MTE]: Use After Free, 0 bytes into a 32-byte allocation at 0x7ae92853a0
x0  0000007cd94227cc  x1  0000007cd94227cc  x2  ffffffffffffffd0  x3  0000007fe81919c0
x4  0000007fe8191a10  x5  0000000000000004  x6  0000005400000051  x7  0000008700000021
x8  0800007ae92853a0  x9  0000000000000000  x10 0000007ae9285000  x11 0000000000000030
x12 000000000000000d  x13 0000007cd941c858  x14 0000000000000054  x15 0000000000000000
x16 0000007cd940c0c8  x17 0000007cd93a1030  x18 0000007cdcac6000  x19 0000007fe8191c78
x20 0000005800eee5c4  x21 0000007fe8191c90  x22 0000000000000002  x23 0000000000000000
x24 0000000000000000  x25 0000000000000000  x26 0000000000000000  x27 0000000000000000
x28 0000000000000000  x29 0000007fe8191b70
lr  0000005800eee0bc  sp  0000007fe8191b60  pc  0000005800eee0c0  pst 0000000060001000

backtrace:
      #00 pc 00000000000010c0  /system/bin/sanitizer-status (test_crash_malloc_uaf()+40) (BuildId: 953fc93301472d0b72709b2b9a9f6f30)
      #01 pc 00000000000014a4  /system/bin/sanitizer-status (test(void (*)())+132) (BuildId: 953fc93301472d0b72709b2b9a9f6f30)
      #02 pc 00000000000019cc  /system/bin/sanitizer-status (main+1032) (BuildId: 953fc93301472d0b72709b2b9a9f6f30)
      #03 pc 00000000000487d8  /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+96) (BuildId: 6ab39e35a2fae7efbe9a04e9bbb14331)

deallocated by thread 13935:
      #00 pc 000000000004643c  /apex/com.android.runtime/lib64/bionic/libc.so (scudo::Allocator<scudo::AndroidConfig, &(scudo_malloc_postinit)>::quarantineOrDeallocateChunk(scudo::Options, void*, scudo::Chunk::UnpackedHeader*, unsigned long)+688) (BuildId: 6ab39e35a2fae7efbe9a04e9bbb14331)
      #01 pc 00000000000421e4  /apex/com.android.runtime/lib64/bionic/libc.so (scudo::Allocator<scudo::AndroidConfig, &(scudo_malloc_postinit)>::deallocate(void*, scudo::Chunk::Origin, unsigned long, unsigned long)+212) (BuildId: 6ab39e35a2fae7efbe9a04e9bbb14331)
      #02 pc 00000000000010b8  /system/bin/sanitizer-status (test_crash_malloc_uaf()+32) (BuildId: 953fc93301472d0b72709b2b9a9f6f30)
      #03 pc 00000000000014a4  /system/bin/sanitizer-status (test(void (*)())+132) (BuildId: 953fc93301472d0b72709b2b9a9f6f30)

allocated by thread 13935:
      #00 pc 0000000000042020  /apex/com.android.runtime/lib64/bionic/libc.so (scudo::Allocator<scudo::AndroidConfig, &(scudo_malloc_postinit)>::allocate(unsigned long, scudo::Chunk::Origin, unsigned long, bool)+1300) (BuildId: 6ab39e35a2fae7efbe9a04e9bbb14331)
      #01 pc 0000000000042394  /apex/com.android.runtime/lib64/bionic/libc.so (scudo_malloc+36) (BuildId: 6ab39e35a2fae7efbe9a04e9bbb14331)
      #02 pc 000000000003cc9c  /apex/com.android.runtime/lib64/bionic/libc.so (malloc+36) (BuildId: 6ab39e35a2fae7efbe9a04e9bbb14331)
      #03 pc 00000000000010ac  /system/bin/sanitizer-status (test_crash_malloc_uaf()+20) (BuildId: 953fc93301472d0b72709b2b9a9f6f30)
      #04 pc 00000000000014a4  /system/bin/sanitizer-status (test(void (*)())+132) (BuildId: 953fc93301472d0b72709b2b9a9f6f30)

Tutti i report sugli arresti anomali di MTE contengono il consueto dump e backtrace del registro per il punto in cui è stato rilevato un problema. La "Causa": riga per un errore rilevato da MTE conterrà "[MTE]" come in dell'esempio precedente, insieme a maggiori dettagli. In questo caso, il tipo specifico di errore rilevato è a "Use After Free" e "0 byte in un'allocazione di 32 byte a 0x7ae92853a0" ci indica le dimensioni e l'indirizzo dell'allocazione e l'offset nell'allocazione a cui abbiamo provato ad accedere.

I report sugli arresti anomali di MTE includono anche tracce di backtrace extra, non solo quelle relative al punto di rilevamento.

"Use After Free" Errori di aggiunta di "dealallocato da" e "assegnato da" al dump di arresto anomalo, che mostra le analisi dello stack nel momento in cui questa memoria è stata distribuita (prima di essere utilizzata) e per il tempo assegnato in precedenza. Indicano anche quale thread è stato l'allocazione/il deal. Tutte e tre le operazioni di rilevamento, allocazione e sono le stesse in questo semplice esempio, ma in casi più complessi del mondo reale non si tratta necessariamente vero, e sapere che differiscono può essere un indizio importante per trovare una relativo alla contemporaneità.

"overflow del buffer" e "Flusso insufficiente del buffer" forniscono solo un ulteriore valore "allocato da" monitoraggio stack, in quanto, per definizione, non sono ancora stati deallocati (o verranno visualizzati come "Da usare dopo senza costi"):

Cause: [MTE]: Buffer Overflow, 0 bytes right of a 32-byte allocation at 0x7ae92853a0
[...]
backtrace:
[...]
allocated by thread 13949:

Nota l'uso della parola "destra" Ciò significa che stiamo comunicando quanti byte supera la dell'allocazione è stato l'accesso errato: un underflow direbbe "left" e sarebbe una serie byte prima dell'inizio dell'allocazione.

Molteplici cause potenziali

A volte i report SEGV_MTESERR contengono la seguente riga:

Note: multiple potential causes for this crash were detected, listing them in decreasing order of likelihood.

Questo accade quando esistono diversi buoni candidati per l'origine dell'errore e non possiamo che è la causa effettiva. Stampiamo un massimo di 3 candidati di questo tipo in ordine approssimativo di probabilità. e lasciare l'analisi all'utente.

signal 11 (SIGSEGV), code 9 (SEGV_MTESERR), fault addr 0x400007b43063db5
backtrace:
    [stack...]

Note: multiple potential causes for this crash were detected, listing them in decreasing order of probability.

Cause: [MTE]: Use After Free, 5 bytes into a 10-byte allocation at 0x7b43063db0
deallocated by thread 6663:
    [stack...]
allocated by thread 6663:
    [stack...]

Cause: [MTE]: Use After Free, 5 bytes into a 6-byte allocation at 0x7b43063db0
deallocated by thread 6663:
    [stack...]

allocated by thread 6663:
    [stack...]

Nell'esempio precedente, sono state rilevate due allocazioni recenti allo stesso indirizzo di memoria che potrebbero sono stati la destinazione prevista dell'accesso alla memoria non valida. Questo può accadere quando le allocazioni riutilizzano memoria libera, ad esempio se hai la sequenza come new, free, new, free, new, free l'accesso. L'allocazione più recente viene stampata per prima.

Euristica dettagliata della determinazione delle cause

La "Causa" di un arresto anomalo dovrebbe mostrare l'allocazione della memoria da cui è stato originariamente derivato il puntatore a cui è stato eseguito l'accesso. Purtroppo, l'hardware MTE non ha modo di tradurre da un puntatore con un tag non corrispondente a un'allocazione. Per spiegare un arresto anomalo SEGV_MTESERR, Android analizza i seguenti dati:

  • L'indirizzo di errore (incluso il tag puntatore).
  • Un elenco di allocazioni recenti dell'heap con analisi dello stack e tag di memoria.
  • Allocazioni attuali (in tempo reale) nelle vicinanze e relativi tag di memoria.

Qualsiasi memoria trasferita di recente all'indirizzo di errore in cui il tag di memoria corrisponde a quello dell'indirizzo di errore è una potenziale situazione di "utilizzo dopo senza costi" causa.

Qualsiasi memoria attiva nelle vicinanze in cui il tag di memoria corrisponde al tag dell'indirizzo di errore è una potenziale "overflow del buffer" (o "Flusso insufficiente del buffer").

Le allocazioni più vicine all'errore, nel tempo o nello spazio, sono considerate più probabili rispetto a quelle lontane.

Poiché la memoria dealallocata viene spesso riutilizzata e il numero di valori di tag diversi è ridotto (meno di 16), non è raro trovare diversi candidati probabili e non è possibile trovare automaticamente la vera causa. Questo è il motivo per cui talvolta nei report degli eventi di Mega Traffico vengono elencate più cause potenziali.

È consigliabile che lo sviluppatore di app esamini le potenziali cause a partire da quella più probabile. Spesso è facile filtrare le cause non correlate in base all'analisi dello stack.

MTE modalità asincrona

Nella modalità asincrona ("asincrona") di MTE, SIGSEGV si arresta in modo anomalo con il codice 8 (SEGV_MTEAERR).

Gli errori SEGV_MTEAERR non si verificano immediatamente quando un programma esegue un accesso alla memoria non valido. Il problema viene rilevato poco dopo l'evento e a quel punto il programma viene interrotto. Questo punto è in genere la chiamata di sistema successiva, ma può anche essere un interruzione del timer, in breve, qualsiasi transizione dallo spazio utente al kernel.

Gli errori SEGV_MTEAERR non conservano l'indirizzo di memoria (viene sempre indicato come "-------"). La backtrace corrisponde al momento in cui è stata rilevata la condizione (ad esempio alla successiva chiamata di sistema o a un altro cambio di contesto) e non al momento in cui è stato eseguito l'accesso non valido.

Ciò significa che l'elemento "main" il backtrace in un arresto anomalo di MTE asincrono in genere non è pertinente. Gli errori in modalità asincrona sono quindi molto più difficili da eseguire il debug rispetto a quelli in modalità di sincronizzazione. Vengono interpretati al meglio per mostrare l'esistenza di un bug di memoria nel codice nelle vicinanze nel thread specificato. I log nella parte inferiore del file di tombstone possono fornire un'indicazione di ciò che è effettivamente successo. In caso contrario, si consiglia di riprodurre l'errore in modalità di sincronizzazione e utilizzare la diagnostica migliore offerta da tale modalità.

Argomenti avanzati

Di fondo, il funzionamento del tagging della memoria assegna un valore di tag casuale a 4 bit (0..15) a ogni allocazione heap. Questo valore viene archiviato in una regione di metadati speciale che corrisponde alla memoria heap allocata. Lo stesso valore viene assegnato al byte più significativo del puntatore heap restituito da funzioni come Malloc() o operatore new().

Quando il controllo dei tag è abilitato nel processo, la CPU confronta automaticamente il byte superiore del puntatore con il tag di memoria per ogni accesso alla memoria. Se i tag non corrispondono, la CPU segnala un errore che genera un arresto anomalo.

A causa del numero limitato di possibili valori dei tag, questo approccio è probabilistico. Qualsiasi posizione di memoria a cui non si dovrebbe accedere con un determinato puntatore, ad esempio fuori dai limiti o dopo la deallocation ("puntatore inclinato"), potrebbe avere un valore di tag diverso e causare un arresto anomalo. Esiste una probabilità del 7% circa di non rilevare una singola occorrenza di un bug. Poiché i valori dei tag vengono assegnati in modo casuale, esiste una probabilità indipendente circa il 93% di rilevare il bug la prossima volta che si verifica.

I valori dei tag possono essere visualizzati nel campo dell'indirizzo di errore e nel dump del registro, come evidenziato di seguito. Questa sezione può essere utilizzata per verificare che i tag siano impostati in modo corretto, nonché per visualizzare altre allocazioni di memoria vicine con lo stesso valore tag, in quanto possono essere potenziali cause di errori oltre a quelle elencate nel report. Ci aspettiamo che questo sia utile principalmente per le persone che lavorano all'implementazione dell'MTE stesso o di altri componenti di sistema di basso livello, piuttosto che per gli sviluppatori.

signal 11 (SIGSEGV), code 9 (SEGV_MTESERR), fault addr 0x0800007ae92853a0
Cause: [MTE]: Use After Free, 0 bytes into a 32-byte allocation at 0x7ae92853a0
    x0  0000007cd94227cc  x1  0000007cd94227cc  x2  ffffffffffffffd0  x3  0000007fe81919c0
    x4  0000007fe8191a10  x5  0000000000000004  x6  0000005400000051  x7  0000008700000021
    x8  0800007ae92853a0  x9  0000000000000000  x10 0000007ae9285000  x11 0000000000000030
    x12 000000000000000d  x13 0000007cd941c858  x14 0000000000000054  x15 0000000000000000
    x16 0000007cd940c0c8  x17 0000007cd93a1030  x18 0000007cdcac6000  x19 0000007fe8191c78
    x20 0000005800eee5c4  x21 0000007fe8191c90  x22 0000000000000002  x23 0000000000000000
    x24 0000000000000000  x25 0000000000000000  x26 0000000000000000  x27 0000000000000000
    x28 0000000000000000  x29 0000007fe8191b70
    lr  0000005800eee0bc  sp  0000007fe8191b60  pc  0000005800eee0c0  pst 0000000060001000

Un tag speciale di memoria viene visualizzata anche nel report sugli arresti anomali che mostra i tag di memoria relativi all'indirizzo di errore. Nell'esempio riportato di seguito, il tag puntatore "4" non corrisponde al tag di memoria "a".

Memory tags around the fault address (0x0400007b43063db5), one tag per 16 bytes:
  0x7b43063500: 0  f  0  2  0  f  0  a  0  7  0  8  0  7  0  e
  0x7b43063600: 0  9  0  8  0  5  0  e  0  f  0  c  0  f  0  4
  0x7b43063700: 0  b  0  c  0  b  0  2  0  1  0  4  0  7  0  8
  0x7b43063800: 0  b  0  c  0  3  0  a  0  3  0  6  0  b  0  a
  0x7b43063900: 0  3  0  4  0  f  0  c  0  3  0  e  0  0  0  c
  0x7b43063a00: 0  3  0  2  0  1  0  8  0  9  0  4  0  3  0  4
  0x7b43063b00: 0  5  0  2  0  5  0  a  0  d  0  6  0  d  0  2
  0x7b43063c00: 0  3  0  e  0  f  0  a  0  0  0  0  0  0  0  4
=>0x7b43063d00: 0  0  0  a  0  0  0  e  0  d  0 [a] 0  f  0  e
  0x7b43063e00: 0  7  0  c  0  9  0  a  0  d  0  2  0  0  0  c
  0x7b43063f00: 0  0  0  6  0  b  0  8  0  3  0  0  0  5  0  e
  0x7b43064000: 0  d  0  2  0  7  0  a  0  7  0  a  0  d  0  8
  0x7b43064100: 0  b  0  2  0  b  0  4  0  1  0  6  0  d  0  4
  0x7b43064200: 0  1  0  6  0  f  0  2  0  f  0  6  0  5  0  c
  0x7b43064300: 0  1  0  4  0  d  0  6  0  f  0  e  0  1  0  8
  0x7b43064400: 0  f  0  4  0  3  0  2  0  1  0  2  0  5  0  6

Anche le sezioni di una tombstone che mostrano i contenuti della memoria intorno a tutti i valori del registro mostrano i relativi valori tag.

memory near x10 ([anon:scudo:primary]):
0000007b4304a000 7e82000000008101 000003e9ce8b53a0  .......~.S......
0700007b4304a010 0000200000006001 0000000000000000  .`... ..........
0000007b4304a020 7c03000000010101 000003e97c61071e  .......|..a|....
0200007b4304a030 0c00007b4304a270 0000007ddc4fedf8  p..C{.....O.}...
0000007b4304a040 84e6000000008101 000003e906f7a9da  ................
0300007b4304a050 ffffffff00000042 0000000000000000  B...............
0000007b4304a060 8667000000010101 000003e9ea858f9e  ......g.........
0400007b4304a070 0000000100000001 0000000200000002  ................
0000007b4304a080 f5f8000000010101 000003e98a13108b  ................
0300007b4304a090 0000007dd327c420 0600007b4304a2b0   .'.}......C{...
0000007b4304a0a0 88ca000000010101 000003e93e5e5ac5  .........Z^>....
0a00007b4304a0b0 0000007dcc4bc500 0300007b7304cb10  ..K.}......s{...
0000007b4304a0c0 0f9c000000010101 000003e9e1602280  ........."`.....
0900007b4304a0d0 0000007dd327c780 0700007b7304e2d0  ..'.}......s{...
0000007b4304a0e0 0d1d000000008101 000003e906083603  .........6......
0a00007b4304a0f0 0000007dd327c3b8 0000000000000000  ..'.}...........