Estensione tagging memoria

Arm v9 introduce Arm Memory Tagging Extension (MTE), un'implementazione hardware della memoria con tag.

Ad alto livello, MTE contrassegna ogni allocazione/deallocazione di memoria con metadati aggiuntivi. Assegna un tag a una posizione di memoria, che quindi può essere associata a puntatori che fanno riferimento a quella posizione di memoria. In fase di esecuzione la CPU controlla che il puntatore e i tag dei metadati corrispondano su ogni caricamento e archiviazione.

In Android 12 l'allocatore di memoria heap del kernel e dello spazio utente può aumentare ogni allocazione con metadati. Ciò aiuta a rilevare i bug use-after-free e buffer-overflow, che sono la fonte più comune di bug di sicurezza della memoria nei nostri codebase.

Modalità operative dell'MTE

MTE ha tre modalità operative:

  • Modalità sincrona (SYNC)
  • Modalità asincrona (ASYNC)
  • Modalità asimmetrica (ASYMM)

Modalità sincrona (SYNC)

Questa modalità è ottimizzata per la correttezza del rilevamento dei bug rispetto alle prestazioni e può essere utilizzata come strumento di rilevamento dei bug preciso, quando è accettabile un sovraccarico di prestazioni più elevato. Quando abilitato, MTE SYNC funge da mitigazione della sicurezza. In caso di mancata corrispondenza del tag, il processore interrompe immediatamente l'esecuzione e termina il processo con SIGSEGV (codice SEGV_MTESERR ) e informazioni complete sull'accesso alla memoria e sull'indirizzo che ha causato l'errore.

Si consiglia di utilizzare questa modalità durante i test come alternativa a HWASan/KASAN o in produzione quando il processo di destinazione rappresenta una superficie di attacco vulnerabile. Inoltre, quando la modalità ASYNC indica la presenza di un bug, è possibile ottenere una segnalazione accurata del bug utilizzando le API runtime per passare l'esecuzione alla modalità SYNC.

Quando viene eseguito in modalità SYNC, l' allocatore Android registra le tracce dello stack per tutte le allocazioni e deallocazioni e le utilizza per fornire migliori rapporti sugli errori che includono una spiegazione di un errore di memoria, come use-after-free o buffer-overflow, e lo stack tracce degli eventi di memoria rilevanti. Tali report forniscono informazioni più contestuali e facilitano il tracciamento e la correzione dei bug.

Modalità asincrona (ASYNC)

Questa modalità è ottimizzata per le prestazioni rispetto alla precisione delle segnalazioni di bug e può essere utilizzata come rilevamento a basso costo per i bug di sicurezza della memoria.
In caso di mancata corrispondenza del tag, il processore continua l'esecuzione fino alla voce del kernel più vicina (ad esempio, una chiamata di sistema o un'interruzione del timer), dove termina il processo con SIGSEGV (codice SEGV_MTEAERR ) senza registrare l'indirizzo che ha causato l'errore o l'accesso alla memoria.
Si consiglia di utilizzare questa modalità in produzione su codebase ben testate in cui è noto che la densità dei bug di sicurezza della memoria è bassa, risultato ottenuto utilizzando la modalità SYNC durante i test.

Modalità asimmetrica (ASYMM)

Una funzionalità aggiuntiva in Arm v8.7-A, la modalità Asymmetric MTE fornisce il controllo sincrono sulle letture della memoria e il controllo asincrono delle scritture della memoria, con prestazioni simili a quelle della modalità ASYNC. Nella maggior parte dei casi, questa modalità rappresenta un miglioramento rispetto alla modalità ASYNC e si consiglia di utilizzarla al posto di ASYNC ogni volta che è disponibile.

Per questo motivo nessuna delle API descritte di seguito menziona la modalità asimmetrica. Invece, il sistema operativo può essere configurato per utilizzare sempre la modalità asimmetrica quando viene richiesta la modalità asincrona. Per ulteriori informazioni consultare la sezione "Configurazione del livello MTE preferito specifico della CPU".

MTE nello spazio utente

Le sezioni seguenti descrivono come è possibile abilitare MTE per i processi e le applicazioni di sistema. MTE è disabilitato per impostazione predefinita, a meno che una delle opzioni seguenti non sia impostata per un processo particolare (vedi di seguito per quali componenti MTE è abilitato).

Abilitazione di MTE utilizzando il sistema di compilazione

Essendo una proprietà a livello di processo, MTE è controllata dall'impostazione del tempo di compilazione dell'eseguibile principale. Le seguenti opzioni consentono di modificare questa impostazione per singoli eseguibili o per intere sottodirectory nell'albero di origine. L'impostazione viene ignorata sulle librerie o su qualsiasi destinazione che non sia né eseguibile né test.

1. Abilitazione di MTE in Android.bp ( esempio ), per un particolare progetto:

Modalità MTE Collocamento
MTE asincrono
  sanitize: {
  memtag_heap: true,
  }
MTE sincrono
  sanitize: {
  memtag_heap: true,
  diag: {
  memtag_heap: true,
  },
  }

o in Android.mk:

Modalità MTE Collocamento
Asynchronous MTE LOCAL_SANITIZE := memtag_heap
Synchronous MTE LOCAL_SANITIZE := memtag_heap
LOCAL_SANITIZE_DIAG := memtag_heap

2. Abilitazione di MTE su una sottodirectory nell'albero di origine utilizzando una variabile di prodotto:

Modalità MTE Includi elenco Elenco esclusi
asincrono PRODUCT_MEMTAG_HEAP_ASYNC_INCLUDE_PATHS MEMTAG_HEAP_ASYNC_INCLUDE_PATHS PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS MEMTAG_HEAP_EXCLUDE_PATHS
sincronizzare PRODUCT_MEMTAG_HEAP_SYNC_INCLUDE_PATHS MEMTAG_HEAP_SYNC_INCLUDE_PATHS

O

Modalità MTE Collocamento
MTE asincrono MEMTAG_HEAP_ASYNC_INCLUDE_PATHS
MTE sincrono MEMTAG_HEAP_SYNC_INCLUDE_PATHS

oppure specificando il percorso di esclusione di un eseguibile:

Modalità MTE Collocamento
MTE asincrono PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS MEMTAG_HEAP_EXCLUDE_PATHS
MTE sincrono

Esempio (utilizzo simile a PRODUCT_CFI_INCLUDE_PATHS )

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

Abilitazione di MTE utilizzando le proprietà di sistema

Le impostazioni di build precedenti possono essere sovrascritte in fase di esecuzione impostando la seguente proprietà di sistema:

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

Dove basename sta per il nome base dell'eseguibile.

Ad esempio, per impostare /system/bin/ping o /data/local/tmp/ping per utilizzare MTE asincrono, utilizzare adb shell setprop arm64.memtag.process.ping async .

Abilitazione di MTE utilizzando una variabile di ambiente

Un altro modo per sovrascrivere l'impostazione di compilazione è definire la variabile di ambiente: MEMTAG_OPTIONS=(off|sync|async) Se sono definite sia la variabile di ambiente che la proprietà di sistema, la variabile ha la precedenza.

Abilitazione di MTE per le applicazioni

Se non specificato, MTE è disabilitato per impostazione predefinita, ma le app che desiderano utilizzare MTE possono farlo impostando android:memtagMode nel tag <application> o <process> in AndroidManifest.xml .

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

Quando impostato sul tag <application> , l'attributo influisce su tutti i processi utilizzati dall'applicazione e può essere sovrascritto per i singoli processi impostando il tag <process> .

A scopo sperimentale, è possibile utilizzare le modifiche alla compatibilità per impostare il valore predefinito dell'attributo memtagMode per un'applicazione che non specifica alcun valore nel manifest (o specifica default ).
Questi possono essere trovati in System > Advanced > Developer options > App Compatibility Changes nel menu delle impostazioni globali. L'impostazione NATIVE_MEMTAG_ASYNC o NATIVE_MEMTAG_SYNC abilita MTE per una particolare applicazione.
In alternativa, questo può essere impostato utilizzando il comando am come segue:

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

Creazione di un'immagine del sistema MTE

Consigliamo vivamente di abilitare MTE su tutti i file binari nativi durante lo sviluppo e il caricamento. Ciò aiuta a rilevare tempestivamente i bug di sicurezza della memoria e fornisce una copertura utente realistica, se abilitata nelle build di test.

Consigliamo vivamente di abilitare MTE in modalità sincrona su tutti i file binari nativi durante lo sviluppo

SANITIZE_TARGET=memtag_heap SANITIZE_TARGET_DIAG=memtag_heap m

Come con qualsiasi variabile nel sistema di compilazione, SANITIZE_TARGET può essere utilizzata come variabile di ambiente o impostazione make (ad esempio, in un file product.mk ).
Tieni presente che ciò abilita MTE per tutti i processi nativi, ma non per le applicazioni (che sono biforcate da zygote64 ) per le quali MTE può essere abilitato seguendo le istruzioni sopra .

Configurazione del livello MTE preferito specifico della CPU

Su alcune CPU le prestazioni di MTE nelle modalità ASYMM o anche SYNC potrebbero essere simili a quelle di ASYNC. Ciò rende utile abilitare controlli più severi su quelle CPU quando è richiesta una modalità di controllo meno severa, al fine di ottenere i vantaggi del rilevamento degli errori dei controlli più severi senza gli svantaggi in termini di prestazioni.
Per impostazione predefinita, i processi configurati per l'esecuzione in modalità ASYNC verranno eseguiti in modalità ASYNC su tutte le CPU. Per configurare il kernel per eseguire questi processi in modalità SYNC su CPU specifiche, il valore sync deve essere scritto nella voce sysfs /sys/devices/system/cpu/cpu<N>/mte_tcf_preferred al momento dell'avvio. Questo può essere fatto con uno script init. Ad esempio, per configurare le CPU 0-1 per eseguire processi in modalità ASYNC in modalità SYNC e le CPU 2-3 per utilizzare l'esecuzione in modalità ASYMM, è possibile aggiungere quanto segue alla clausola init di uno script init del fornitore:

  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

Gli oggetti contrassegnati per rimozione dei processi in modalità ASYNC in esecuzione in modalità SYNC conterranno un'analisi dello stack precisa della posizione dell'errore di memoria. Tuttavia, non includeranno un'analisi dello stack di allocazione o deallocazione. Queste analisi dello stack sono disponibili solo se il processo è configurato per l'esecuzione in modalità SYNC.

int mallopt(M_THREAD_DISABLE_MEM_INIT, level)

dove level è 0 o 1.
Disabilita l'inizializzazione della memoria in malloc ed evita di modificare i tag di memoria a meno che non sia necessario per la correttezza.

int mallopt(M_MEMTAG_TUNING, level)

dove level è:

  • M_MEMTAG_TUNING_BUFFER_OVERFLOW
  • M_MEMTAG_TUNING_UAF

Seleziona la strategia di allocazione dei tag.

  • L'impostazione predefinita è M_MEMTAG_TUNING_BUFFER_OVERFLOW .
  • M_MEMTAG_TUNING_BUFFER_OVERFLOW - consente il rilevamento deterministico di bug di overflow e underflow del buffer lineare assegnando valori di tag distinti ad allocazioni adiacenti. Questa modalità ha una possibilità leggermente ridotta di rilevare bug use-after-free perché solo la metà dei possibili valori dei tag è disponibile per ciascuna posizione di memoria. Tieni presente che MTE non è in grado di rilevare l'overflow all'interno dello stesso granulo di tag (blocco allineato a 16 byte) e può perdere piccoli overflow anche in questa modalità. Tale overflow non può essere la causa del danneggiamento della memoria, poiché la memoria all'interno di un granulo non viene mai utilizzata per più allocazioni.
  • M_MEMTAG_TUNING_UAF - abilita tag randomizzati in modo indipendente per una probabilità uniforme di circa il 93% di rilevare bug sia spaziali (buffer overflow) che temporali (uso dopo libero).

Oltre alle API sopra descritte, gli utenti esperti potrebbero voler tenere presente quanto segue:

  • L'impostazione del registro hardware PSTATE.TCO può sopprimere temporaneamente il controllo dei tag ( esempio ). Ad esempio, quando si copia un intervallo di memoria con contenuti di tag sconosciuti o si affronta un collo di bottiglia delle prestazioni in un hot loop.
  • Quando si utilizza M_HEAP_TAGGING_LEVEL_SYNC , il gestore degli arresti anomali del sistema fornisce informazioni aggiuntive come analisi dello stack di allocazione e deallocazione. Questa funzionalità richiede l'accesso ai bit del tag ed è abilitata passando il flag SA_EXPOSE_TAGBITS durante l'impostazione del gestore del segnale. Si consiglia a qualsiasi programma che imposta il proprio gestore di segnale e delega arresti anomali sconosciuti a quello di sistema di fare lo stesso.

MTE nel kernel

Per abilitare KASAN con accelerazione MTE per il kernel, configurare il kernel con CONFIG_KASAN=y , CONFIG_KASAN_HW_TAGS=y . Queste configurazioni sono abilitate per impostazione predefinita sui kernel GKI, a partire da Android 12-5.10 .
Questo può essere controllato all'avvio utilizzando i seguenti argomenti della riga di comando:

  • kasan=[on|off] - abilita o disabilita KASAN (default: on )
  • kasan.mode=[sync |async ] - scegli tra la modalità sincrona e asincrona (impostazione predefinita: sync )
  • kasan.stacktrace=[on|off] - se raccogliere le tracce dello stack (impostazione predefinita: on )
    • anche la raccolta dell'analisi dello stack richiede stack_depot_disable=off .
  • kasan.fault=[report|panic] - se stampare solo il report o anche mandare in panico il kernel (default: report ). Indipendentemente da questa opzione, il controllo dei tag viene disabilitato dopo il primo errore segnalato.

Consigliamo vivamente di utilizzare la modalità SYNC durante il caricamento, lo sviluppo e il test. Questa opzione dovrebbe essere abilitata globalmente per tutti i processi utilizzando la variabile d'ambiente o con il sistema di compilazione . In questa modalità, i bug vengono rilevati nelle prime fasi del processo di sviluppo, la base di codice viene stabilizzata più rapidamente e si evita il costo del rilevamento dei bug in una fase successiva della produzione.

Consigliamo vivamente di utilizzare la modalità ASYNC in produzione. Ciò fornisce uno strumento a basso costo per rilevare la presenza di bug di sicurezza della memoria in un processo, nonché un'ulteriore difesa approfondita. Una volta rilevato un bug, lo sviluppatore può sfruttare le API runtime per passare alla modalità SYNC e ottenere un'analisi dello stack accurata da un set di utenti campione.

Consigliamo vivamente di configurare il livello MTE preferito specifico della CPU per il SoC. La modalità Asymm ha in genere le stesse caratteristiche prestazionali di ASYNC ed è quasi sempre preferibile ad essa. I core piccoli in ordine spesso mostrano prestazioni simili in tutte e tre le modalità e possono essere configurati per preferire SYNC.

Gli sviluppatori dovrebbero verificare la presenza di arresti anomali controllando /data/tombstones , logcat o monitorando la pipeline DropboxManager del fornitore per i bug degli utenti finali. Per ulteriori informazioni sul debug del codice nativo Android, consulta le informazioni qui .

Componenti della piattaforma abilitati MTE

In Android 12, numerosi componenti di sistema critici per la sicurezza utilizzano MTE ASYNC per rilevare arresti anomali dell'utente finale e agire come ulteriore livello di difesa approfondita. Questi componenti sono:

  • Demoni e utilità di rete (ad eccezione di netd )
  • Bluetooth, SecureElement, HAL NFC e applicazioni di sistema
  • demone statsd
  • system_server
  • zygote64 (per consentire alle applicazioni di aderire all'utilizzo di MTE)

Questi target sono stati selezionati in base ai seguenti criteri:

  • Un processo privilegiato (definito come un processo che ha accesso a qualcosa che il dominio SELinux unprivileged_app non ha)
  • Elabora input non affidabili ( regola del due )
  • Rallentamento delle prestazioni accettabile (il rallentamento non crea latenza visibile all'utente)

Incoraggiamo i fornitori ad abilitare MTE in produzione per più componenti, seguendo i criteri sopra menzionati. Durante lo sviluppo consigliamo di testare questi componenti utilizzando la modalità SYNC, per rilevare bug facilmente risolvibili e valutare l'impatto di ASYNC sulle loro prestazioni.
In futuro, Android prevede di espandere l'elenco dei componenti di sistema su cui è abilitato MTE, guidato dalle caratteristiche prestazionali dei prossimi progetti hardware.