Scudo

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 .