Google si impegna a promuovere l'equità razziale per le comunità nere. Vedi come.
Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

Controllo dell'integrità del flusso

A partire dal 2016, circa l'86% di tutte le vulnerabilità su Android sono legate alla sicurezza della memoria. La maggior parte delle vulnerabilità viene sfruttata dagli aggressori che modificano il normale flusso di controllo di un'applicazione per eseguire attività dannose arbitrarie con tutti i privilegi dell'applicazione sfruttata. L'integrità del flusso di controllo (CFI) è un meccanismo di sicurezza che non consente modifiche al grafico del flusso di controllo originale di un file binario compilato, rendendo notevolmente più difficile eseguire tali attacchi.

In Android 8.1, abbiamo abilitato l'implementazione di CFI da parte di LLVM nello stack multimediale. In Android 9, abbiamo abilitato CFI in più componenti e anche nel kernel. Il CFI di sistema è attivo per impostazione predefinita ma è necessario abilitare il CFI del kernel.

Il CFI di LLVM richiede la compilazione con Link-Time Optimization (LTO) . LTO conserva la rappresentazione LLVM bitcode dei file oggetto fino al tempo di collegamento, il che consente al compilatore di ragionare meglio su quali ottimizzazioni possono essere eseguite. L'abilitazione di LTO riduce le dimensioni del file binario finale e migliora le prestazioni, ma aumenta i tempi di compilazione. Nei test su Android, la combinazione di LTO e CFI si traduce in un trascurabile sovraccarico di dimensioni e prestazioni del codice; in alcuni casi entrambi sono migliorati.

Per ulteriori dettagli tecnici su CFI e su come vengono gestiti gli altri controlli di controllo a termine, consultare la documentazione di progettazione di LLVM .

Esempi e fonte

CFI viene fornito dal compilatore e aggiunge la strumentazione al file binario durante il tempo di compilazione. Supportiamo CFI nella toolchain di Clang e nel sistema di build Android in AOSP.

CFI è abilitato per impostazione predefinita per i dispositivi Arm64 per l'insieme di componenti in /platform/build/target/product/cfi-common.mk . È anche direttamente abilitato in un set di file makefile / blueprint dei componenti multimediali, come /platform/frameworks/av/media/libmedia/Android.bp e /platform/frameworks/av/cmds/stagefright/Android.mk .

Sistema di attuazione CFI

CFI è abilitato per impostazione predefinita se si utilizza Clang e il sistema di generazione Android. Poiché CFI aiuta a proteggere gli utenti Android, non è necessario disabilitarlo.

In effetti, ti consigliamo vivamente di abilitare CFI per componenti aggiuntivi. I candidati ideali sono il codice nativo privilegiato o il codice nativo che elabora l'input dell'utente non attendibile. Se stai usando clang e il sistema di build Android, puoi abilitare CFI nei nuovi componenti aggiungendo alcune righe ai tuoi makefile o file di progetto.

Supporto CFI nei makefile

Per abilitare CFI in un file make, come /platform/frameworks/av/cmds/stagefright/Android.mk , aggiungere:

LOCAL_SANITIZE := cfi
# Optional features
LOCAL_SANITIZE_DIAG := cfi
LOCAL_SANITIZE_BLACKLIST := cfi_blacklist.txt
  • LOCAL_SANITIZE specifica CFI come disinfettante durante la compilazione.
  • LOCAL_SANITIZE_DIAG attiva la modalità diagnostica per CFI. La modalità diagnostica stampa ulteriori informazioni di debug in logcat durante gli arresti anomali, utile durante lo sviluppo e il test delle build. Assicurati di rimuovere la modalità diagnostica dalle build di produzione, però.
  • LOCAL_SANITIZE_BLACKLIST consente ai componenti di disabilitare selettivamente la strumentazione CFI per singole funzioni o file sorgente. È possibile utilizzare una lista nera come ultima risorsa per risolvere eventuali problemi che l'utente potrebbe altrimenti affrontare. Per ulteriori dettagli, consultare Disabilitazione CFI .

Supporto CFI nei file di progetto

Per abilitare CFI in un file di progetto, come /platform/frameworks/av/media/libmedia/Android.bp , aggiungere:

   sanitize: {
        cfi: true,
        diag: {
            cfi: true,
        },
        blacklist: "cfi_blacklist.txt",
    },

Risoluzione dei problemi

Se si abilita CFI in nuovi componenti, è possibile che si verifichino alcuni problemi con errori di mancata corrispondenza del tipo di funzione ed errori di mancata corrispondenza del tipo di codice assembly .

Si verificano errori di mancata corrispondenza del tipo di funzione perché CFI limita le chiamate indirette a saltare solo a funzioni che hanno lo stesso tipo dinamico del tipo statico utilizzato nella chiamata. CFI limita le chiamate di funzione membro virtuale e non virtuale per saltare solo agli oggetti che sono una classe derivata del tipo statico dell'oggetto utilizzato per effettuare la chiamata. Ciò significa che quando si dispone di codice che viola una di queste ipotesi, la strumentazione aggiunta da CFI si interromperà. Ad esempio, la traccia dello stack mostra un SIGABRT e logcat contiene una riga sull'integrità del flusso di controllo che trova una mancata corrispondenza.

Per risolvere questo problema, assicurarsi che la funzione chiamata abbia lo stesso tipo dichiarato staticamente. Ecco due esempi di CL:

Un altro possibile problema sta provando ad abilitare CFI nel codice che contiene chiamate indirette all'assembly. Poiché il codice assembly non viene digitato, ciò comporta una mancata corrispondenza del tipo.

Per risolvere questo problema, creare wrapper di codice nativo per ogni chiamata di assembly e assegnare agli wrapper la stessa firma della funzione del poiner chiamante. Il wrapper può quindi chiamare direttamente il codice assembly. Poiché le filiali dirette non sono strumentate da CFI (non possono essere reimpostate in fase di esecuzione e quindi non rappresentano un rischio per la sicurezza), questo risolverà il problema.

Se ci sono troppe funzioni di assemblaggio e non possono essere tutte riparate, è anche possibile inserire nella blacklist tutte le funzioni che contengono chiamate indirette all'assemblaggio. Questo non è raccomandato in quanto disabilita i controlli CFI su queste funzioni, aprendo così la superficie di attacco.

Disabilitazione CFI

Non abbiamo osservato alcun sovraccarico di prestazioni, quindi non dovresti disabilitare CFI. Tuttavia, se si verifica un impatto rivolto all'utente, è possibile disabilitare in modo selettivo CFI per singole funzioni o file di origine fornendo un file della lista nera del disinfettante al momento della compilazione. La lista nera indica al compilatore di disabilitare la strumentazione CFI in posizioni specificate.

Il sistema di build Android fornisce supporto per blacklist per componente (che consente di scegliere file sorgente o singole funzioni che non riceveranno la strumentazione CFI) sia per Make che Soong. Per maggiori dettagli sul formato di un file della lista nera, consultare i documenti Clang a monte .

Validazione

Attualmente, non esistono test CTS specifici per CFI. Assicurati invece che i test CTS vengano superati con o senza CFI abilitato per verificare che il CFI non abbia alcun impatto sul dispositivo.