Debug e mitigazione degli errori di memoria

Android supporta più strumenti per il debug degli errori di memoria. Ognuno presenta dei compromessi, quindi continua a leggere per decidere quale sia la soluzione migliore per il tuo caso d'uso. Questo documento fornisce una panoramica degli strumenti disponibili per consentirti di decidere quali approfondire, ma ha lo scopo di essere conciso, quindi leggi la documentazione specifica dello strumento per maggiori dettagli.

TL;DR

  • Utilizza un linguaggio memory-safe, se possibile, per impedire gli errori di memoria
  • Utilizza sempre PAC/BTI per mitigare gli attacchi ROP/JOP
  • Utilizza sempre GWP-ASan per rilevare errori di memoria rari in produzione
  • Utilizza HWASan per rilevare gli errori di memoria durante i test
  • I dispositivi compatibili con MTE non sono disponibili a livello generale. Questa operazione non sarà utile finché non cambierà
  • Utilizza ASan durante i test solo come ultima risorsa

Lingue sicure per la memoria

Un linguaggio memory-safe è l'unico modo per evitare e ridurre al minimo gli errori di memoria. Gli altri strumenti in questa pagina possono aiutarti a rendere il codice con problemi di sicurezza della memoria più sicuro e affidabile, ma l'utilizzo di un linguaggio con problemi di sicurezza della memoria elimina l'intera classe di problemi.

I linguaggi di programmazione ufficialmente supportati per la sicurezza della memoria per Android sono Java e Kotlin. La maggior parte delle applicazioni per Android è più facile da sviluppare in uno di questi linguaggi.

Detto questo, ci sono sviluppatori di app che distribuiscono codice scritto in Rust e, se stai leggendo questa pagina, probabilmente hai un buon motivo per aver bisogno di codice nativo (portabilità, prestazioni o entrambi). Rust è la scelta migliore per il codice nativo sicuro per la memoria su Android. Il team NDK non è necessariamente in grado di aiutarti a risolvere i problemi che potresti riscontrare se scegli questa strada, ma siamo interessati a ricevere informazioni in merito.

PAC/BTI

Pointer Authentication and Branch Target Identification, noti anche come PAC/BTI, sono strumenti di mitigazione adatti all'uso in produzione. Sebbene siano tecnologie separate, sono controllate dallo stesso flag del compilatore, pertanto vengono sempre utilizzate insieme.

Queste funzionalità sono compatibili con le versioni precedenti dei dispositivi che non le supportano perché le nuove istruzioni utilizzate non vengono eseguite sui dispositivi precedenti. È inoltre necessario avere un kernel e una versione del sistema operativo sufficientemente recenti. La ricerca di paca e bti in /proc/cpuinfo ti consente di sapere se hai hardware sufficientemente nuovo e un kernel sufficientemente nuovo. Android 12 (API 31) offre il supporto necessario per lo spazio utente.

Pro:

  • Può essere attivato in tutte le build senza causare problemi su dispositivi o kernel meno recenti (ma assicurati di aver eseguito effettivamente il test su una combinazione di dispositivo/kernel/OS che lo supporta).

Contro:

  • Disponibile solo per le app a 64 bit
  • Non riduce gli errori sui dispositivi che non la supportano
  • 1% di sovraccarico delle dimensioni del codice

GWP-Asan

GWP-ASan può essere utilizzato per rilevare errori di memoria in campo, ma la frequenza di campionamento è troppo bassa per essere una mitigazione efficace.

Pro:

  • Nessun sovraccarico significativo della CPU o della memoria
  • Facile da implementare: non richiede la ricostruzione del codice nativo
  • Compatibile con le app a 32 bit

Contro:

  • Una frequenza di campionamento bassa richiede un numero elevato di utenti per trovare i bug in modo efficace
  • Rileva solo errori dell'heap, non errori dello stack

HWASan

Lo strumento di convalida degli indirizzi hardware, noto anche come HWASan, è la soluzione migliore per rilevare gli errori di memoria durante i test. È più utile se utilizzato con i test automatici, in particolare se esegui test di fuzz, ma a seconda delle esigenze di prestazioni della tua app potrebbe essere utilizzabile anche su smartphone di fascia alta in un ambiente di dogfood.

Pro:

  • Nessun falso positivo
  • Rileva classi di errori aggiuntive che ASan non è in grado di rilevare (utilizzo dello stack dopo il ritorno)
  • Tasso di falsi negativi inferiore rispetto a MTE (1 su 256 rispetto a 1 su 16)
  • Overhead della memoria inferiore rispetto ad ASan, la sua alternativa più vicina

Contro:

  • Overhead significativo della CPU (~100%), delle dimensioni del codice (~50%) e della memoria (10-35%)
  • Fino all'API 34 e alla versione r26 dell'NDK, è necessario eseguire il flashing di un'immagine compatibile con HWASan
  • Funziona solo sulle app a 64 bit

MTE

L'estensione di tagging della memoria, nota anche come MTE, è un'alternativa meno costosa a HWASan. Oltre alle funzionalità di debug e test, puoi utilizzarlo per rilevare e mitigare la corruzione della memoria in produzione. Se hai l'hardware per testare le build MTE, devi attivarla.

Pro:

  • Un overhead sufficientemente basso da essere tollerabile in produzione per molte app
  • Nessun falso positivo
  • Non richiede la ricostruzione del codice per rilevare gli errori dell'heap (ma per rilevare gli errori dello stack)

Contro:

  • Nel 2024 non sono disponibili commercialmente dispositivi con MTE abilitato per impostazione predefinita, ma la documentazione di Arm spiega come attivare MTE per i test su Pixel 8/Pixel 8 Pro.
  • Tasso di falsi negativi di 1 su 16 rispetto a 1 su 256 di HWASan
  • Disponibile solo per le app a 64 bit
  • Richiede la creazione di librerie separate per scegliere come target sia i dispositivi con MTE sia quelli senza

ASan

Lo strumento di convalida degli indirizzi, noto anche come ASan, è lo strumento più antico e più ampiamente disponibile. È utile per rilevare errori di memoria durante i test e i problemi di debug che interessano solo i vecchi dispositivi in cui non è disponibile nessuno degli altri strumenti. Se possibile, preferisci HWASan.

Pro:

  • Ampiamente disponibile. Potrebbe funzionare su dispositivi meno recenti di KitKat
  • Nessun falso positivo o negativo se utilizzato correttamente

Contro:

  • Difficoltà a compilare e pacchettizzare correttamente
  • Il sovraccarico più elevato di tutte le opzioni: circa il 100% della CPU, circa il 50% delle dimensioni del codice e circa il 100% dell'utilizzo della memoria
  • Non più supportato
  • Presenta bug noti che non verranno corretti