Scudo è un allocatore di memoria dinamico in modalità utente, o allocatore di heap , progettato per essere resistente alle vulnerabilità correlate all'heap (come overflow del buffer basato su heap , use after free e double free ) mantenendo le prestazioni. Fornisce le primitive standard di allocazione e deallocazione del C (come malloc e free), nonché le primitive C++ (come new ed delete).
Scudo è più una mitigazione che un rilevatore di errori di memoria completo come AddressSanitizer (ASan) .
A partire dal rilascio di Android 11, scudo viene utilizzato per tutto il codice nativo (ad eccezione dei dispositivi con memoria ridotta, dove viene ancora utilizzato jemalloc). In fase di esecuzione, tutte le allocazioni e deallocazioni dell'heap nativo vengono gestite da Scudo per tutti gli eseguibili e le relative dipendenze della libreria e il processo viene interrotto se viene rilevato un danneggiamento o un comportamento sospetto nell'heap.
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 ed è stato aggiunto il supporto a Soong e Make per consentire una facile abilitazione dell'allocatore in un binario.
Puoi abilitare o disabilitare la mitigazione 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 delle opzioni da analizzare. Questa funzione deve avere il seguente prototipo:extern "C" const char *__scudo_default_options()
. - Dinamicamente: utilizza la variabile di ambiente
SCUDO_OPTIONS
contenente la stringa delle opzioni da analizzare. Le opzioni definite in questo modo sovrascrivono qualsiasi definizione effettuata tramite__scudo_default_options
.
Sono disponibili le seguenti opzioni.
Opzione | Impostazione predefinita a 64 bit | Impostazione predefinita 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. Impostando sia questo che ThreadLocalQuarantineSizeKb su zero si 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 potrebbe ridurre l'utilizzo della memoria ma potrebbe aumentare il conflitto sulla quarantena globale. Impostando sia questo che QuarantineSizeKb su zero si 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 in caso di mancata corrispondenza tra le dimensioni di nuovo ed eliminato. |
ZeroContents | false | false | Abilita il contenuto di blocchi zero durante l'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 falliscono o restituiscono null (a seconda del valore di allocator_may_return_null ), finché l'RSS non torna indietro per consentire nuove allocazioni. |
allocator_release_to_os_interval_ms | N / A | 5000 | Interessa solo 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. |
Validazione
Attualmente non esistono 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 termina il processo. Le tracce dello stack che portano alla terminazione vengono aggiunte nel registro di sistema. L'output solitamente inizia con Scudo ERROR:
seguito da un breve riepilogo del problema insieme ad eventuali indicazioni.
Di seguito è riportato un elenco dei messaggi di errore correnti e delle relative potenziali cause:
-
corrupted chunk header
: la verifica del checksum dell'intestazione del blocco non è riuscita. Ciò è probabilmente dovuto a due cose: l'intestazione è stata sovrascritta (parzialmente o totalmente) oppure il puntatore passato alla funzione non è un pezzo. -
race on chunk header
: due thread diversi stanno tentando di manipolare la stessa intestazione contemporaneamente. Questo di solito è sintomatico di una condizione di competizione o di una generale mancanza di blocco durante l'esecuzione di operazioni su quel pezzo. -
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 viene messo in quarantena quando si tenta di riciclarlo. Un doppio gratis è il motivo tipico 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 è fuori allineamento. -
allocation type mismatch
: quando questa opzione è abilitata, una funzione di deallocazione chiamata su un blocco deve corrispondere al tipo di funzione 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, si verifica una mancata corrispondenza tra la dimensione passata durante la deallocazione di un blocco e la dimensione richiesta durante l'allocazione. Si tratta in genere di un problema del compilatore o di una confusione di tipo sull'oggetto da deallocare. -
RSS limit exhausted
: Il massimo RSS opzionalmente specificato è stato superato.
Se stai eseguendo il debug di un arresto anomalo del 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 di app HWASan .