Non definitoBehaviorSanitizer

UnfineBehaviorSanitizer (UBSan) esegue la strumentazione in fase di compilazione per verificare vari tipi di comportamento indefinito. Sebbene UBSan sia in grado di rilevare molti bug di comportamento non definiti , Android supporta:

  • allineamento
  • bool
  • limiti
  • enum
  • float-cast-overflow
  • float-dividi-per-zero
  • divisione intera per zero
  • attributo non nullo
  • nullo
  • ritorno
  • restituisce-attributo-nonnull
  • base del cambio
  • esponente di spostamento
  • overflow intero con segno
  • irraggiungibile
  • overflow di interi senza segno
  • legato a vla

unsigned-integer-overflow, sebbene non abbia un comportamento tecnicamente indefinito, è incluso nel sanitizer e utilizzato in molti moduli Android, inclusi i componenti mediaserver, per eliminare qualsiasi vulnerabilità latente di integer-overflow.

Implementazione

Nel sistema di build Android, puoi abilitare UBSan a livello globale o locale. Per abilitare UBSan a livello globale, imposta SANITIZE_TARGET in Android.mk. Per abilitare UBSan a livello di modulo, imposta LOCAL_SANITIZE e specifica i comportamenti non definiti che desideri cercare in Android.mk. Per esempio:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_CFLAGS := -std=c11 -Wall -Werror -O0

LOCAL_SRC_FILES:= sanitizer-status.c

LOCAL_MODULE:= sanitizer-status

LOCAL_SANITIZE := alignment bounds null unreachable integer
LOCAL_SANITIZE_DIAG := alignment bounds null unreachable integer

include $(BUILD_EXECUTABLE)

E la configurazione del progetto equivalente (Android.bp):

cc_binary {

    cflags: [
        "-std=c11",
        "-Wall",
        "-Werror",
        "-O0",
    ],

    srcs: ["sanitizer-status.c"],

    name: "sanitizer-status",

    sanitize: {
        misc_undefined: [
            "alignment",
            "bounds",
            "null",
            "unreachable",
            "integer",
        ],
        diag: {
            misc_undefined: [
                "alignment",
                "bounds",
                "null",
                "unreachable",
                "integer",
            ],
        },
    },

}

Scorciatoie UBSan

Android ha anche due scorciatoie, integer e default-ub , per abilitare una serie di disinfettanti contemporaneamente. integer abilita integer-divide-by-zero , signed-integer-overflow e unsigned-integer-overflow . default-ub abilita i controlli che presentano problemi minimi di prestazioni del compilatore: bool, integer-divide-by-zero, return, returns-nonnull-attribute, shift-exponent, unreachable and vla-bound . La classe intera sanitizer può essere utilizzata con SANITIZE_TARGET e LOCAL_SANITIZE, mentre default-ub può essere utilizzata solo con SANITIZE_TARGET.

Migliore segnalazione degli errori

L'implementazione UBSan predefinita di Android richiama una funzione specifica quando viene riscontrato un comportamento indefinito. Per impostazione predefinita, questa funzione è interrotta. Tuttavia, a partire da ottobre 2016, UBSan su Android dispone di una libreria runtime opzionale che fornisce segnalazioni di errori più dettagliate, incluso il tipo di comportamento indefinito riscontrato, informazioni sul file e sulla riga del codice sorgente. Per abilitare questa segnalazione di errori con controlli di numeri interi, aggiungi quanto segue a un file Android.mk:

LOCAL_SANITIZE:=integer
LOCAL_SANITIZE_DIAG:=integer

Il valore LOCAL_SANITIZE abilita il disinfettante durante la compilazione. LOCAL_SANITIZE_DIAG attiva la modalità diagnostica per il disinfettante specificato. È possibile impostare LOCAL_SANITIZE e LOCAL_SANITIZE_DIAG su valori diversi, ma sono abilitati solo i controlli in LOCAL_SANITIZE. Se un controllo non è specificato in LOCAL_SANITIZE, ma è specificato in LOCAL_SANITIZE_DIAG, il controllo non è abilitato e i messaggi diagnostici non vengono forniti.

Ecco un esempio delle informazioni fornite dalla libreria runtime UBSan:

pixel-xl:/ # sanitizer-status ubsan
sanitizer-status/sanitizer-status.c:53:6: runtime error: unsigned integer overflow: 18446744073709551615 + 1 cannot be represented in type 'size_t' (aka 'unsigned long')

Sanificazione dell'overflow intero

Gli overflow involontari di numeri interi possono causare danneggiamento della memoria o vulnerabilità legate alla divulgazione di informazioni nelle variabili associate agli accessi alla memoria o alle allocazioni di memoria. Per contrastare questo problema, abbiamo aggiunto i disinfettanti per overflow di numeri interi con e senza segno UnDefinitedBehaviorSanitizer (UBSan) di Clang per rafforzare il framework multimediale in Android 7.0. In Android 9, abbiamo ampliato UBSan per coprire più componenti e migliorato il supporto del sistema di build.

Questo è progettato per aggiungere controlli sulle operazioni/istruzioni aritmetiche, che potrebbero overflow, per interrompere in sicurezza un processo se si verifica un overflow. Questi disinfettanti possono mitigare un'intera classe di corruzione della memoria e vulnerabilità relative alla divulgazione di informazioni in cui la causa principale è un overflow di numeri interi, come la vulnerabilità originale Stagefright.

Esempi e fonte

Integer Overflow Sanitization (IntSan) viene fornito dal compilatore e aggiunge strumentazione al file binario durante la fase di compilazione per rilevare gli overflow aritmetici. È abilitato per impostazione predefinita in vari componenti della piattaforma, ad esempio /platform/external/libnl/Android.bp .

Implementazione

IntSan utilizza i disinfettanti per overflow di numeri interi con segno e senza segno di UBSan. Questa mitigazione è abilitata a livello di modulo. Aiuta a mantenere sicuri i componenti critici di Android e non deve essere disabilitato.

Ti consigliamo vivamente di abilitare la sanitizzazione di Integer Overflow per componenti aggiuntivi. I candidati ideali sono il codice nativo privilegiato o il codice nativo che analizza l'input dell'utente non attendibile. Esiste un piccolo sovraccarico delle prestazioni associato al disinfettante che dipende dall'utilizzo del codice e dalla prevalenza delle operazioni aritmetiche. Aspettatevi una piccola percentuale di sovraccarico e verificate se le prestazioni sono un problema.

Supporto di IntSan nei makefile

Per abilitare IntSan in un makefile, aggiungi:

LOCAL_SANITIZE := integer_overflow
    # Optional features
    LOCAL_SANITIZE_DIAG := integer_overflow
    LOCAL_SANITIZE_BLOCKLIST := modulename_BLOCKLIST.txt
  • LOCAL_SANITIZE accetta un elenco separato da virgole di disinfettanti, con integer_overflow che è un insieme preconfezionato di opzioni per i singoli disinfettanti di overflow di numeri interi con segno e senza segno con una BLOCKLIST predefinita .
  • LOCAL_SANITIZE_DIAG attiva la modalità diagnostica per i disinfettanti. Utilizzare la modalità diagnostica solo durante i test poiché questa non verrà interrotta in caso di overflow, annullando completamente il vantaggio in termini di sicurezza della mitigazione. Vedere Risoluzione dei problemi per ulteriori dettagli.
  • LOCAL_SANITIZE_BLOCKLIST consente di specificare un file BLOCKLIST per impedire la pulizia delle funzioni e dei file di origine. Vedere Risoluzione dei problemi per ulteriori dettagli.

Se desideri un controllo più granulare, abilita i disinfettanti singolarmente utilizzando uno o entrambi i flag:

LOCAL_SANITIZE := signed-integer-overflow, unsigned-integer-overflow
    LOCAL_SANITIZE_DIAG := signed-integer-overflow, unsigned-integer-overflow

Supporto di IntSan nei file del progetto

Per abilitare la sanificazione dell'overflow dei numeri interi in un file blueprint, come /platform/external/libnl/Android.bp , aggiungi:

   sanitize: {
          integer_overflow: true,
          diag: {
              integer_overflow: true,
          },
          BLOCKLIST: "modulename_BLOCKLIST.txt",
       },

Come con i file make, la proprietà integer_overflow è un insieme preconfezionato di opzioni per i singoli disinfettanti di overflow di numeri interi firmati e non firmati con una BLOCKLIST predefinita .

Il set di proprietà diag abilita la modalità diagnostica per i disinfettanti. Utilizzare la modalità diagnostica solo durante i test. La modalità diagnostica non si interrompe in caso di overflow, il che annulla completamente il vantaggio in termini di sicurezza derivante dalla mitigazione nelle build degli utenti. Vedere Risoluzione dei problemi per ulteriori dettagli.

La proprietà BLOCKLIST consente la specifica di un file BLOCKLIST che consente agli sviluppatori di impedire la pulizia delle funzioni e dei file di origine. Vedere Risoluzione dei problemi per ulteriori dettagli.

Per abilitare singolarmente gli igienizzanti utilizzare:

   sanitize: {
          misc_undefined: ["signed-integer-overflow", "unsigned-integer-overflow"],
          diag: {
              misc_undefined: ["signed-integer-overflow",
                               "unsigned-integer-overflow",],
          },
          BLOCKLIST: "modulename_BLOCKLIST.txt",
       },

Risoluzione dei problemi

Se stai abilitando la sanificazione dell'overflow di numeri interi in nuovi componenti o fai affidamento su librerie della piattaforma che hanno avuto la sanificazione dell'overflow di numeri interi, potresti riscontrare alcuni problemi con overflow di numeri interi benigni che causano interruzioni. È necessario testare i componenti con la sanificazione abilitata per garantire che possano emergere traboccamenti benigni.

Per trovare interruzioni causate dalla sanificazione nelle build degli utenti, cercare SIGABRT si arresta in modo anomalo con messaggi di interruzione che indicano un overflow rilevato da UBSan, come ad esempio:

pid: ###, tid: ###, name: Binder:###  >>> /system/bin/surfaceflinger <<<
    signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
    Abort message: 'ubsan: sub-overflow'

L'analisi dello stack dovrebbe includere la funzione che causa l'interruzione, tuttavia, gli overflow che si verificano nelle funzioni inline potrebbero non essere evidenti nell'analisi dello stack.

Per determinare più facilmente la causa principale, abilitare la diagnostica nella libreria che attiva l'interruzione e tentare di riprodurre l'errore. Con la diagnostica abilitata, il processo non verrà interrotto e continuerà invece a essere eseguito. Non interrompere aiuta a massimizzare il numero di overflow benigni in un particolare percorso di esecuzione senza dover ricompilare dopo aver corretto ciascun bug. La diagnostica produce un messaggio di errore che include il numero di riga e il file sorgente che causa l'interruzione:

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:2188:32: runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'size_t' (aka 'unsigned long')

Una volta individuata l'operazione aritmetica problematica, assicurarsi che l'overflow sia benigno e intenzionale (ad esempio, non abbia implicazioni sulla sicurezza). È possibile risolvere l'interruzione del disinfettante:

  • Refactoring del codice per evitare l'overflow ( esempio )
  • Overflow esplicitamente tramite le funzioni __builtin_*_overflow di Clang ( esempio )
  • Disabilitare la sanificazione nella funzione specificando l'attributo no_sanitize ( esempio )
  • Disabilitare la sanitizzazione di una funzione o di un file sorgente tramite un file BLOCKLIST ( esempio )

Dovresti utilizzare la soluzione più granulare possibile. Ad esempio, una funzione di grandi dimensioni con molte operazioni aritmetiche e una singola operazione in overflow dovrebbe avere la singola operazione sottoposta a refactoring anziché l'intera funzione BLOCKLIST.

I modelli comuni che possono provocare overflow benigni includono:

  • Cast impliciti in cui si verifica un overflow senza segno prima del cast su un tipo con segno ( esempio )
  • Eliminazioni di elenchi collegati che diminuiscono l'indice del ciclo durante l'eliminazione ( esempio )
  • Assegnazione di un tipo senza segno a -1 invece di specificare il valore massimo effettivo ( esempio )
  • Cicli che decrementano un intero senza segno nella condizione ( esempio , esempio )

Si consiglia agli sviluppatori di garantire che, nei casi in cui il disinfettante rileva un trabocco, si tratti effettivamente di un fenomeno benigno, senza effetti collaterali indesiderati o implicazioni per la sicurezza, prima di disabilitare la sanificazione.

Disabilitare IntSan

È possibile disabilitare IntSan con BLOCKLIST o attributi di funzione. Disabilitarlo con parsimonia e solo quando il refactoring del codice è altrimenti irragionevole o se si verificano problemi di sovraccarico delle prestazioni.

Consulta la documentazione Clang upstream per ulteriori informazioni sulla disabilitazione di IntSan con attributi di funzione e formattazione del file BLOCKLIST . La BLOCKLIST deve avere come ambito il disinfettante specifico utilizzando i nomi delle sezioni che specificano il disinfettante di destinazione per evitare di influenzare altri disinfettanti.

Validazione

Attualmente non esistono test CTS specifici per la sanificazione dell'overflow intero. Assicurati invece che i test CTS superino con o senza IntSan abilitato per verificare che non influisca sul dispositivo.

Sanificazione dei limiti

BoundsSanitizer (BoundSan) aggiunge strumentazione ai file binari per inserire controlli dei limiti attorno agli accessi agli array. Questi controlli vengono aggiunti se il compilatore non può dimostrare in fase di compilazione che l'accesso sarà sicuro e se la dimensione dell'array sarà nota in fase di esecuzione, in modo che possa essere verificata. Android 10 implementa BoundSan in Bluetooth e codec. BoundSan viene fornito dal compilatore ed è abilitato per impostazione predefinita in vari componenti della piattaforma.

Implementazione

BoundSan utilizza il disinfettante per confini di UBSan . Questa mitigazione è abilitata a livello di modulo. Aiuta a mantenere sicuri i componenti critici di Android e non deve essere disabilitato.

Ti consigliamo vivamente di abilitare BoundSan per componenti aggiuntivi. I candidati ideali sono il codice nativo privilegiato o il codice nativo complesso che analizza l'input dell'utente non attendibile. Il sovraccarico prestazionale associato all'abilitazione di BoundSan dipende dal numero di accessi all'array che non possono essere dimostrati sicuri. Aspettatevi in ​​media una piccola percentuale di spese generali e verificate se le prestazioni sono un problema.

Abilitazione di BoundSan nei file del progetto

BoundSan può essere abilitato nei file blueprint aggiungendo "bounds" alla proprietà sanitize misc_undefined per i moduli binari e di libreria:

    sanitize: {
       misc_undefined: ["bounds"],
       diag: {
          misc_undefined: ["bounds"],
       },
       BLOCKLIST: "modulename_BLOCKLIST.txt",
diag

La proprietà diag abilita la modalità diagnostica per i disinfettanti. Utilizzare la modalità diagnostica solo durante i test. La modalità diagnostica non si interrompe in caso di overflow, il che annulla il vantaggio in termini di sicurezza della mitigazione e comporta un sovraccarico delle prestazioni più elevato, pertanto non è consigliata per le build di produzione.

LISTA DI BLOCCATI

La proprietà BLOCKLIST consente la specifica di un file BLOCKLIST che gli sviluppatori possono utilizzare per impedire la pulizia delle funzioni e dei file di origine. Utilizzare questa proprietà solo se le prestazioni sono un problema e i file/funzioni di destinazione contribuiscono in modo sostanziale. Controlla manualmente questi file/funzioni per garantire che gli accessi all'array siano sicuri. Vedere Risoluzione dei problemi per ulteriori dettagli.

Abilitazione di BoundSan nei makefile

BoundSan può essere abilitato nei makefile aggiungendo "bounds" alla variabile LOCAL_SANITIZE per i moduli binari e di libreria:

    LOCAL_SANITIZE := bounds
    # Optional features
    LOCAL_SANITIZE_DIAG := bounds
    LOCAL_SANITIZE_BLOCKLIST := modulename_BLOCKLIST.txt

LOCAL_SANITIZE accetta un elenco di disinfettanti separati da una virgola.

LOCAL_SANITIZE_DIAG attiva la modalità diagnostica. Utilizzare la modalità diagnostica solo durante i test. La modalità diagnostica non si interrompe in caso di overflow, il che annulla il vantaggio in termini di sicurezza della mitigazione e comporta un sovraccarico delle prestazioni più elevato, pertanto non è consigliata per le build di produzione.

LOCAL_SANITIZE_BLOCKLIST consente la specifica di un file BLOCKLIST che consente agli sviluppatori di impedire che le funzioni e i file di origine vengano disinfettati. Utilizzare questa proprietà solo se le prestazioni sono un problema e i file/funzioni di destinazione contribuiscono in modo sostanziale. Controlla manualmente questi file/funzioni per garantire che gli accessi all'array siano sicuri. Vedere Risoluzione dei problemi per ulteriori dettagli.

Disabilitare BoundSan

È possibile disabilitare BoundSan nelle funzioni e nei file di origine con BLOCKLIST o attributi di funzione. È meglio mantenere BoundSan abilitato, quindi disabilitarlo solo se la funzione o il file sta creando un grande sovraccarico di prestazioni e la fonte è stata rivista manualmente.

Per ulteriori informazioni sulla disabilitazione di BoundSan con attributi di funzione e formattazione del file BLOCKLIST , fare riferimento alla documentazione di Clang LLVM. Ambito della BLOCKLIST al disinfettante specifico utilizzando i nomi delle sezioni che specificano il disinfettante di destinazione per evitare di influenzare altri disinfettanti.

Validazione

Non esistono test CTS specifici per BoundSan. Assicurati invece che i test CTS superino con o senza BoundSan abilitato per verificare che non influisca sul dispositivo.

Risoluzione dei problemi

Testare accuratamente i componenti dopo aver abilitato BoundSan per garantire che eventuali accessi fuori limite precedentemente non rilevati vengano risolti.

Gli errori BoundSan possono essere facilmente identificati poiché includono il seguente messaggio di interruzione rimozione definitiva:

    pid: ###, tid: ###, name: Binder:###  >>> /system/bin/foobar <<<
    signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
    Abort message: 'ubsan: out-of-bounds'

Quando si esegue in modalità diagnostica, il file di origine, il numero di riga e il valore dell'indice vengono stampati su logcat . Per impostazione predefinita, questa modalità non genera un messaggio di interruzione. Esaminare logcat per verificare eventuali errori.

    external/foo/bar.c:293:13: runtime error: index -1 out of bounds for type 'int [24]'