Google 致力于为黑人社区推动种族平等。查看具体举措
Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

Igienizzanti LLVM

LLVM, l'infrastruttura del compilatore utilizzata per creare Android, contiene più componenti che eseguono analisi statiche e dinamiche. Di questi componenti, i disinfettanti, in particolare AddressSanitizer e UndefinedBehaviorSanitizer, possono essere ampiamente utilizzati per analizzare Android. I disinfettanti sono componenti di strumentazione basati sul compilatore contenuti in external / compiler-rt che possono essere utilizzati durante lo sviluppo e il test per eliminare i bug e migliorare Android. L'attuale set di disinfettanti di Android può scoprire e diagnosticare molti bug di uso improprio della memoria e comportamenti indefiniti potenzialmente pericolosi.

È consigliabile che le build Android si avviino ed eseguano con disinfettanti abilitati, come AddressSanitizer e UndefinedBehaviorSanitizer. Questa pagina introduce AddressSanitizer, UndefinedBehaviorSanitizer e KernelAddressSanitizer, mostra come possono essere utilizzati all'interno del sistema di build Android e fornisce file Android.mk e Android.bp di esempio che creano componenti nativi con questi disinfettanti abilitati.

AddressSanitizer

AddressSanitizer (ASan) è una funzionalità di strumentazione basata sul compilatore che rileva molti tipi di errori di memoria nel codice C / C ++ in fase di esecuzione. ASan può rilevare molte classi di errori di memoria, tra cui:

  • Accesso alla memoria fuori dai limiti
  • Doppio libero
  • Uso dopo gratuito

Android consente la strumentazione ASan a livello di build completo e a livello di app con asanwrapper.

AddressSanitizer combina la strumentazione di tutte le chiamate di funzione relative alla memoria, inclusi alloca, malloc e free, e riempie tutte le variabili e le regioni di memoria allocate con la memoria che attiva un callback ASan quando viene letto o scritto.

La strumentazione consente ad ASan di rilevare bug di utilizzo della memoria non validi, inclusi double-free e use-after scope, return e free, mentre il riempimento della regione di memoria rileva letture o scritture fuori limite. Se si verifica una lettura o una scrittura in questa regione di riempimento, ASan la rileva e fornisce informazioni per aiutare a diagnosticare la violazione della memoria, inclusi lo stack di chiamate, la mappa della memoria shadow, il tipo di violazione della memoria, ciò che è stato letto o scritto, l'istruzione che ha causato il violazione e il contenuto della memoria.

pixel-xl:/ # sanitizer-status                                                                                            
=================================================================
==14164==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x0032000054b0 at pc 0x005df16ffc3c bp 0x007fc236fdf0 sp 0x007fc236fdd0
WRITE of size 1 at 0x0032000054b0 thread T0
    #0 0x5df16ffc3b in test_crash_malloc sanitizer-status/sanitizer-status.c:36:13
    #1 0x5df17004e3 in main sanitizer-status/sanitizer-status.c:76:7
    #2 0x794cf665f3 in __libc_init (/system/lib64/libc.so+0x1b5f3)
    #3 0x5df16ffa53 in do_arm64_start (/system/bin/sanitizer-status+0xa53)

0x0032000054b0 is located 0 bytes to the right of 32-byte region [0x003200005490,0x0032000054b0)
allocated by thread T0 here:
    #0 0x794d0bdc67 in malloc (/system/lib64/libclang_rt.asan-aarch64-android.so+0x74c67)
    #1 0x5df16ffb47 in test_crash_malloc sanitizer-status/sanitizer-status.c:34:25
    #2 0x5df17004e3 in main sanitizer-status/sanitizer-status.c:76:7
    #3 0x794cf665f3 in __libc_init (/system/lib64/libc.so+0x1b5f3)
    #4 0x5df16ffa53 in do_arm64_start (/system/bin/sanitizer-status+0xa53)
    #5 0x794df78893  (<unknown module>)

SUMMARY: AddressSanitizer: heap-buffer-overflow sanitizer-status/sanitizer-status.c:36:13 in test_crash_malloc

A volte, il processo di rilevamento dei bug può sembrare non deterministico, specialmente per i bug che richiedono una configurazione speciale o tecniche più avanzate, come l'adescamento dell'heap o lo sfruttamento delle condizioni di gara. Molti di questi bug non sono immediatamente evidenti e potrebbero far emergere migliaia di istruzioni dalla violazione della memoria che era la vera causa principale. ASan strumentalizza tutte le funzioni relative alla memoria e riempie i dati con aree a cui non è possibile accedere senza attivare una richiamata ASan. Ciò significa che le violazioni della memoria vengono rilevate nell'istante in cui si verificano, invece di attendere un danneggiamento che provoca un arresto anomalo. Ciò è estremamente utile nella scoperta di bug e nella diagnosi della causa principale.

Per verificare che ASAN funzioni su un dispositivo di destinazione, Android ha incluso l'eseguibile asan_test. L'eseguibile asan_test verifica e convalida la funzionalità ASAN su un dispositivo di destinazione, fornendo messaggi di diagnostica con lo stato di ciascun test. Quando si utilizza una build Android ASAN, si trova in /data/nativetest/asan_test/asan_test o /data/nativetest64/asan_test/asan_test per impostazione predefinita.

UndefinedBehaviorSanitizer

UndefinedBehaviorSanitizer (UBSan) esegue la strumentazione in fase di compilazione per verificare la presenza di vari tipi di comportamento non definito. Mentre UBSan è in grado di rilevare molti comportamenti non definiti , Android supporta alignment, bool, bounds, enum, float-cast-overflow, float-divide-by-zero, integer-divide-by-zero, nonnull-attribute, null, return, Restituisce attributo non nullo, base-spostamento, esponente-spostamento, overflow-intero con segno, non raggiungibile, overflow-intero-senza segno e vincolato a vla. unsigned-integer-overflow, sebbene non sia tecnicamente un comportamento indefinito, è incluso nel sanitizer e utilizzato in molti moduli Android, inclusi i componenti mediaserver, per eliminare eventuali vulnerabilità latenti 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 indefiniti 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)

Il sistema di build Android non supporta ancora la diagnostica dettagliata nei file blueprint quanto i makefile. Ecco l'equivalente più vicino scritto come progetto (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: {
            undefined : true
        },
    },

}

Scorciatoie UBSan

Android ha anche due scorciatoie, integer e default-ub , per abilitare un set di disinfettanti allo stesso tempo. integer abilita integer-divide-by-zero , signed-integer-overflow e unsigned-integer-overflow . default-ub abilita i controlli che hanno problemi minimi di prestazioni del compilatore: bool, integer-divide-by-zero, return, return-nonnull-attribute, shift-exponent, unreachable e vla-bound. La classe integer 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 di UBSan predefinita di Android richiama una funzione specificata quando viene rilevato un comportamento indefinito. Per impostazione predefinita, questa funzione è interrotta. Tuttavia, a partire da ottobre 2016, UBSan su Android dispone di una libreria di runtime opzionale che fornisce una segnalazione degli errori più dettagliata, incluso il tipo di comportamento indefinito riscontrato, informazioni su file e riga di codice sorgente. Per abilitare questa segnalazione degli errori con controlli 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 non vengono forniti messaggi di diagnostica.

Ecco un esempio delle informazioni fornite dalla libreria runtime di 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')

Kernel Address Sanitizer

Analogamente ai disinfettanti basati su LLVM per i componenti dello spazio utente, Android include Kernel Address Sanitizer (KASAN). KASAN è una combinazione di kernel e modifiche in fase di compilazione che si traducono in un sistema strumentato che consente una più semplice scoperta dei bug e analisi della causa principale.

KASAN può rilevare molti tipi di violazioni della memoria nel kernel. Può anche rilevare letture e scritture fuori limite su stack, heap e variabili globali e può rilevare use-after-free e double free.

Simile ad ASAN, KASAN utilizza una combinazione di strumentazione funzione di memoria in fase di compilazione e memoria shadow per tenere traccia degli accessi alla memoria in fase di esecuzione. In KASAN, un ottavo dello spazio di memoria del kernel è dedicato alla memoria shadow, che determina se un accesso alla memoria è valido o meno.

KASAN è supportato sulle architetture x86_64 e arm64. È stato parte del kernel upstream dalla 4.0 ed è stato eseguito il backport su kernel basati su Android 3.18. KASAN è stato testato su kernel Android compilati con gcc basato su 4.9.2.

Oltre a KASAN, kcov è un'altra modifica del kernel utile per i test. kcov è stato sviluppato per consentire test fuzz guidati dalla copertura nel kernel. Misura la copertura in termini di input di syscall ed è utile con i sistemi di fuzz , come syzkaller .

Implementazione

Per compilare un kernel con KASAN e kcov abilitati, aggiungi i seguenti flag di build alla configurazione della build del tuo kernel:

CONFIG_KASAN 
CONFIG_KASAN_INLINE 
CONFIG_TEST_KASAN 
CONFIG_KCOV 
CONFIG_SLUB 
CONFIG_SLUB_DEBUG 
CONFIG_CC_OPTIMIZE_FOR_SIZE

E rimuovendo quanto segue:

CONFIG_SLUB_DEBUG_ON 
CONFIG_SLUB_DEBUG_PANIC_ON 
CONFIG_KASAN_OUTLINE 
CONFIG_KERNEL_LZ4

Quindi compilare e aggiornare il kernel come al solito. Il kernel KASAN è notevolmente più grande dell'originale. Se applicabile, modificare i parametri di avvio e le impostazioni del bootloader per tenerne conto.

Dopo aver aggiornato il kernel, controlla i log di avvio del kernel per vedere se KASAN è abilitato e in esecuzione. Il kernel si avvierà con le informazioni sulla mappa della memoria per KASAN, come ad esempio:

...
[    0.000000] c0      0 Virtual kernel memory layout:
[    0.000000] c0      0     kasan   : 0xffffff8000000000 - 0xffffff9000000000   (    64 GB)
[    0.000000] c0      0     vmalloc : 0xffffff9000010000 - 0xffffffbdbfff0000   (   182 GB)
[    0.000000] c0      0     vmemmap : 0xffffffbdc0000000 - 0xffffffbfc0000000   (     8 GB maximum)
[    0.000000] c0      0               0xffffffbdc0000000 - 0xffffffbdc3f95400   (    63 MB actual)
[    0.000000] c0      0     PCI I/O : 0xffffffbffa000000 - 0xffffffbffb000000   (    16 MB)
[    0.000000] c0      0     fixed   : 0xffffffbffbdfd000 - 0xffffffbffbdff000   (     8 KB)
[    0.000000] c0      0     modules : 0xffffffbffc000000 - 0xffffffc000000000   (    64 MB)
[    0.000000] c0      0     memory  : 0xffffffc000000000 - 0xffffffc0fe550000   (  4069 MB)
[    0.000000] c0      0       .init : 0xffffffc001d33000 - 0xffffffc001dce000   (   620 KB)
[    0.000000] c0      0       .text : 0xffffffc000080000 - 0xffffffc001d32284   ( 29385 KB)
...

Ed è così che apparirà un bug:

[   18.539668] c3      1 ==================================================================
[   18.547662] c3      1 BUG: KASAN: null-ptr-deref on address 0000000000000008
[   18.554689] c3      1 Read of size 8 by task swapper/0/1
[   18.559988] c3      1 CPU: 3 PID: 1 Comm: swapper/0 Tainted: G        W      3.18.24-xxx #1
[   18.569275] c3      1 Hardware name: Android Device
[   18.577433] c3      1 Call trace:
[   18.580739] c3      1 [<ffffffc00008b32c>] dump_backtrace+0x0/0x2c4
[   18.586985] c3      1 [<ffffffc00008b600>] show_stack+0x10/0x1c
[   18.592889] c3      1 [<ffffffc001481194>] dump_stack+0x74/0xc8
[   18.598792] c3      1 [<ffffffc000202ee0>] kasan_report+0x11c/0x4d0
[   18.605038] c3      1 [<ffffffc00020286c>] __asan_load8+0x20/0x80
[   18.611115] c3      1 [<ffffffc000bdefe8>] android_verity_ctr+0x8cc/0x1024
[   18.617976] c3      1 [<ffffffc000bcaa2c>] dm_table_add_target+0x3dc/0x50c
[   18.624832] c3      1 [<ffffffc001bdbe60>] dm_run_setup+0x50c/0x678
[   18.631082] c3      1 [<ffffffc001bda8c0>] prepare_namespace+0x44/0x1ac
[   18.637676] c3      1 [<ffffffc001bda170>] kernel_init_freeable+0x328/0x364
[   18.644625] c3      1 [<ffffffc001478e20>] kernel_init+0x10/0xd8
[   18.650613] c3      1 ==================================================================

Inoltre, se i moduli sono abilitati nel kernel, è possibile caricare il modulo del kernel test_kasan per ulteriori test. Il modulo tenta di accedere alla memoria fuori limite e di utilizzarlo dopo averlo liberato ed è utile per testare KASAN su un dispositivo di destinazione.