Scudo è un allocatore di memoria dinamico in modalità utente, o allocatore di heap , progettato per resistere alle vulnerabilità correlate all'heap (come buffer overflow basato su heap , use after free e double free ) pur mantenendo le prestazioni. Fornisce le primitive standard C di allocazione e deallocazione (come malloc e free), così come le primitive C++ (come new e delete).
Scudo è più una mitigazione che un vero e proprio rilevatore di errori di memoria come AddressSanitizer (ASan) .
Dalla versione Android 11, scudo viene utilizzato per tutto il codice nativo (eccetto sui dispositivi con poca memoria, dove viene ancora utilizzato jemalloc). In fase di esecuzione, tutte le allocazioni e le deallocazioni native dell'heap 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 su 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 file 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 in base al processo in diversi modi:
- Staticamente: definire una funzione
__scudo_default_options
nel programma che restituisca la stringa delle opzioni da analizzare. Questa funzione deve avere il seguente prototipo:extern "C" const char *__scudo_default_options()
. - Dinamicamente: utilizzare 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 | 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 this 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 il conflitto sulla quarantena globale. L'impostazione di this 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 in caso di mancata corrispondenza tra le dimensioni di nuovo ed eliminato. |
ZeroContents | false | false | Abilita contenuti di blocco zero su allocazione e 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 ), fino a quando l'RSS 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 al 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 vengano superati con o senza Scudo abilitato per un determinato file binario per verificare che non abbia alcun impatto 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 al registro di sistema. L'output di solito inizia con Scudo ERROR:
seguito da un breve riepilogo del problema insieme a eventuali suggerimenti.
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) o 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 condizione di competizione o di una generale mancanza 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 è allocato quando si tenta di liberarlo o non è in quarantena quando si tenta di riciclarlo. Un doppio gratuito è 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 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, 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 deallocato. -
RSS limit exhausted
: è stato superato il massimo RSS opzionalmente specificato.
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 .
,Scudo è un allocatore di memoria dinamico in modalità utente, o allocatore di heap , progettato per resistere alle vulnerabilità correlate all'heap (come buffer overflow basato su heap , use after free e double free ) pur mantenendo le prestazioni. Fornisce le primitive standard C di allocazione e deallocazione (come malloc e free), così come le primitive C++ (come new e delete).
Scudo è più una mitigazione che un vero e proprio rilevatore di errori di memoria come AddressSanitizer (ASan) .
Dalla versione Android 11, scudo viene utilizzato per tutto il codice nativo (eccetto sui dispositivi con poca memoria, dove viene ancora utilizzato jemalloc). In fase di esecuzione, tutte le allocazioni e le deallocazioni native dell'heap 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 su 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 file 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 in base al processo in diversi modi:
- Staticamente: definire una funzione
__scudo_default_options
nel programma che restituisca la stringa delle opzioni da analizzare. Questa funzione deve avere il seguente prototipo:extern "C" const char *__scudo_default_options()
. - Dinamicamente: utilizzare 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 | 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 this 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 il conflitto sulla quarantena globale. L'impostazione di this 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 in caso di mancata corrispondenza tra le dimensioni di nuovo ed eliminato. |
ZeroContents | false | false | Abilita contenuti di blocco zero su allocazione e 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 ), fino a quando l'RSS 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 al 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 vengano superati con o senza Scudo abilitato per un determinato file binario per verificare che non abbia alcun impatto 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 al registro di sistema. L'output di solito inizia con Scudo ERROR:
seguito da un breve riepilogo del problema insieme a eventuali suggerimenti.
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) o 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 condizione di competizione o di una generale mancanza di blocco durante l'esecuzione di operazioni su quel blocco. -
invalid chunk state
: il blocco non si trova nello stato previsto per una determinata operazione, ad esempio non è allocato quando si tenta di liberarlo o non viene messo in quarantena quando si tenta di riciclarlo. Un doppio gratuito è 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 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, 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 deallocato. -
RSS limit exhausted
: è stato superato il massimo RSS opzionalmente specificato.
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 .