Scudo

Scudo è un allocatore di memoria dinamico in modalità utente, o allocatore di heap , progettato per essere resiliente alle vulnerabilità relative all'heap (come l' overflow del buffer basato su heap , use after free e double free ) mantenendo le prestazioni. Fornisce le primitive di allocazione e deallocazione C standard (come malloc e free), nonché le primitive C++ (come new ed delete).

Scudo è più una mitigazione che un rilevatore di errori di memoria a tutti gli effetti come AddressSanitizer (ASan) .

A partire dalla versione Android 11, lo scudo viene utilizzato per tutto il codice nativo (tranne sui dispositivi con memoria insufficiente, dove viene ancora utilizzato jemalloc). In fase di esecuzione, tutte le allocazioni e le deallocazioni dell'heap native sono gestite da Scudo per tutti gli eseguibili e le relative dipendenze dalla libreria e il processo viene interrotto se nell'heap viene rilevato un danneggiamento o un comportamento sospetto.

In Android 10, lo scudo doveva essere abilitato su base binaria impostando l' LOCAL_SANITIZE := scudo nel file .mk o sanitize: { scudo: true, } nel file .bp.

Scudo è open source e fa parte del progetto compiler-rt di LLVM. La documentazione è disponibile all'indirizzo https://llvm.org/docs/ScudoHardenedAllocator.html . Il runtime Scudo viene fornito come parte della toolchain Android e il supporto è stato aggiunto a Soong e Make per consentire una facile abilitazione dell'allocatore in un binario.

È possibile abilitare o disabilitare l'attenuazione aggiuntiva all'interno dell'allocatore utilizzando le opzioni descritte di seguito.

Personalizzazione

Alcuni parametri dell'allocatore possono essere definiti per processo in diversi modi:

  • Staticamente: definire una funzione __scudo_default_options nel programma che restituisce la stringa di opzioni da analizzare. Questa funzione deve avere il seguente prototipo: extern "C" const char *__scudo_default_options() .
  • In modo dinamico: utilizzare la variabile di ambiente SCUDO_OPTIONS contenente la stringa di opzioni da analizzare. Le opzioni definite in questo modo prevalgono su qualsiasi definizione effettuata tramite __scudo_default_options .

Sono disponibili le seguenti opzioni.

Opzione predefinito a 64 bit predefinito a 32 bit Descrizione
QuarantineSizeKb 256 64 La dimensione (in KB) della quarantena utilizzata per ritardare l'effettiva deallocazione dei blocchi. Un valore inferiore può ridurre l'utilizzo della memoria ma diminuire l'efficacia della mitigazione; un valore negativo ritorna ai valori predefiniti. L'impostazione di questo e ThreadLocalQuarantineSizeKb su zero disabilita completamente la quarantena.
QuarantineChunksUpToSize 2048 512 La dimensione (in byte) fino alla quale i blocchi possono essere messi in quarantena.
ThreadLocalQuarantineSizeKb 64 16 La dimensione (in KB) della cache per thread utilizzata per scaricare la quarantena globale. Un valore inferiore può ridurre l'utilizzo della memoria ma potrebbe aumentare la contesa sulla quarantena globale. L'impostazione di questo e QuarantineSizeKb su zero disabilita completamente la quarantena.
DeallocationTypeMismatch false false Abilita la segnalazione degli errori su malloc/delete, new/free, new/delete[]
DeleteSizeMismatch true true Abilita la segnalazione degli errori sulla mancata corrispondenza tra le dimensioni del nuovo e dell'eliminazione.
ZeroContents false false Abilita il contenuto a blocchi zero sull'allocazione e la deallocazione.
allocator_may_return_null false false Specifica che l'allocatore può restituire null quando si verifica un errore reversibile, invece di terminare il processo.
hard_rss_limit_mb 0 0 Quando l'RSS del processo raggiunge questo limite, il processo termina.
soft_rss_limit_mb 0 0 Quando l'RSS del processo raggiunge questo limite, ulteriori allocazioni non riescono o restituiscono null (a seconda del valore di allocator_may_return_null ), fino a quando l'RSS non torna indietro per consentire nuove allocazioni.
allocator_release_to_os_interval_ms N / A 5000 Influisce solo su un allocatore a 64 bit. Se impostato, tenta di rilasciare la memoria inutilizzata nel sistema operativo, ma non più spesso di questo intervallo (in millisecondi). Se il valore è negativo, la memoria non viene rilasciata al sistema operativo.
abort_on_error true true Se impostato, lo strumento chiama abort() invece di _exit() dopo aver stampato il messaggio di errore.

Convalida

Attualmente non ci sono test CTS specifici per Scudo. Assicurati invece che i test CTS superino con o senza Scudo abilitato per un determinato binario per verificare che non influisca sul dispositivo.

Risoluzione dei problemi

Se viene rilevato un problema irreversibile, l'allocatore visualizza un messaggio di errore nel descrittore di errore standard e quindi interrompe il processo. Le tracce dello stack che portano alla terminazione vengono aggiunte nel registro di sistema. L'output di solito inizia con Scudo ERROR: seguito da un breve riassunto del problema insieme a eventuali puntatori.

Di seguito è riportato un elenco dei messaggi di errore correnti e delle loro potenziali cause:

  • corrupted chunk header : la verifica del checksum dell'intestazione del blocco non è riuscita. Ciò è probabilmente dovuto a una delle due cose: l'intestazione è stata sovrascritta (parzialmente o totalmente) oppure il puntatore passato alla funzione non è un blocco.
  • race on chunk header : due thread diversi stanno tentando di manipolare la stessa intestazione contemporaneamente. Questo di solito è sintomatico di una race condition o della mancanza generale di blocco durante l'esecuzione di operazioni su quel blocco.
  • invalid chunk state : il blocco non è nello stato previsto per una determinata operazione, ad esempio, non viene allocato quando si tenta di liberarlo o non è messo in quarantena quando si tenta di riciclarlo. Un doppio libero è il tipico motivo di questo errore.
  • misaligned pointer : i requisiti di allineamento di base sono fortemente applicati: 8 byte su piattaforme a 32 bit e 16 byte su piattaforme a 64 bit. Se un puntatore passato alle nostre funzioni non si adatta a quelle, il puntatore passato a una delle funzioni non è allineato.
  • allocation type mismatch : quando questa opzione è abilitata, una funzione di deallocazione chiamata su un blocco deve corrispondere al tipo di funzione che è stata chiamata per allocarlo. Questo tipo di mancata corrispondenza può introdurre problemi di sicurezza.
  • invalid sized delete : quando viene utilizzato l'operatore di eliminazione di dimensioni C++14 e il controllo facoltativo è abilitato, esiste una mancata corrispondenza tra la dimensione passata durante la deallocazione di un blocco e la dimensione richiesta durante l'allocazione. Questo è in genere un problema del compilatore o una confusione di tipo sull'oggetto che viene deallocato.
  • RSS limit exhausted : il massimo RSS specificato facoltativamente è stato superato.

Se stai eseguendo il debug di un arresto anomalo nel sistema operativo stesso, puoi utilizzare una build del sistema operativo HWASan . Se stai eseguendo il debug di un arresto anomalo in un'app, è possibile utilizzare anche una build dell'app HWASan .