Controlla l'integrità del flusso

Fino al 2016, circa l’86% di tutte le vulnerabilità su Android riguardava la sicurezza della memoria. correlati. La maggior parte delle vulnerabilità viene sfruttata da utenti malintenzionati che modificano il normale di controllo del flusso di un'app per eseguire attività dannose con tutti i privilegi dell'app sfruttata. Flusso di controllo per l'integrità (CFI) è un meccanismo di sicurezza che non consente modifiche al di controllo originale di un file binario compilato, rendendo molto più difficile per eseguire tali attacchi.

In Android 8.1, abbiamo attivato l'implementazione di LLVM di CFI nello stack multimediale. Nella Android 9, abbiamo abilitato CFI in altri componenti e anche nel kernel. CFI sistema è per impostazione predefinita, ma devi abilitare CFI del kernel.

CFI di LLVM richiede la compilazione con Ottimizzazione del tempo del collegamento (LTO). LTO conserva la rappresentazione in bitcode LLVM dei file oggetto link-time, che permette al compilatore di ragionare meglio sulle ottimizzazioni che è possibile eseguire. L'abilitazione dell'LTO riduce la dimensione del file binario finale e migliora ma aumenta il tempo di compilazione. Durante i test su Android, la combinazione di LTO e CFI comporta un overhead trascurabile rispetto alle dimensioni e alle prestazioni del codice; in un in pochi casi entrambi sono migliorati.

Per ulteriori dettagli tecnici su CFI e su come vengono eseguiti altri controlli di inoltro viene gestita, consulta la progettazione LLVM documentazione.

Esempi e fonte

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

La funzione CFI è abilitata per impostazione predefinita per i dispositivi Arm64 per il gruppo di componenti in /platform/build/target/product/cfi-common.mk. Inoltre, viene attivata direttamente in un insieme di componenti multimediali. crearefile/progetto file, ad esempio /platform/frameworks/av/media/libmedia/Android.bp e /platform/frameworks/av/cmds/stagefright/Android.mk.

Implementazione di CFI del sistema

CFI è abilitato per impostazione predefinita se utilizzi Clang e il sistema di build Android. Dato che CFI aiuta a proteggere gli utenti di Android, non dovresti disattivarla.

Infatti, consigliamo vivamente di abilitare CFI per i componenti aggiuntivi. I candidati ideali sono il codice nativo privilegiato, ovvero il codice nativo che elabora input utente non attendibile. Se utilizzi clang e il sistema di build Android, puoi abilitare CFI nei nuovi componenti aggiungendo qualche riga ai file makefile o file di progetto.

Supporto di CFI nei makefile

Per attivare CFI in un file di creazione, ad esempio /platform/frameworks/av/cmds/stagefright/Android.mk, aggiungi:

LOCAL_SANITIZE := cfi
# Optional features
LOCAL_SANITIZE_DIAG := cfi
LOCAL_SANITIZE_BLACKLIST := cfi_blacklist.txt

  • LOCAL_SANITIZE specifica CFI come sanitizzatore durante creare.
  • LOCAL_SANITIZE_DIAG attiva la modalità diagnostica per CFI. La modalità diagnostica stampa altre informazioni di debug in logcat durante , che è utile durante lo sviluppo e il test delle build. Marca assicurati di rimuovere la modalità diagnostica nelle build di produzione.
  • LOCAL_SANITIZE_BLACKLIST consente ai componenti di scegliere disattivare la strumentazione CFI per singole funzioni o file di origine. Tu puoi utilizzare una lista nera come ultima risorsa per risolvere eventuali problemi altrimenti potrebbe esistere. Per ulteriori dettagli, vedi Disattivazione di CFI.

Supporto di CFI nei file di progetto

Per attivare CFI in un file progetto, ad esempio /platform/frameworks/av/media/libmedia/Android.bp, aggiungi:

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

Risoluzione dei problemi

Se attivi CFI in nuovi componenti, potresti riscontrare alcuni problemi con errori di mancata corrispondenza del tipo di funzione e corrispondenza del tipo di codice di assemblaggio errori.

Gli errori di mancata corrispondenza del tipo di funzione si verificano perché CFI limita le chiamate indirette solo passa alle funzioni che hanno lo stesso tipo dinamico del tipo statico utilizzato nella chiamata. CFI limita le chiamate di funzione membro virtuali e non virtuali solo al passaggio agli oggetti che sono una classe derivata del tipo statico dell'oggetto utilizzato effettuare la chiamata. Ciò significa che quando un codice viola uno di questi dei dati, la strumentazione aggiunta da CFI verrà interrotta. Ad esempio, l'analisi dello stack mostra un SIGABRT e logcat contiene una riga sul flusso di controllo e rileva un'errata integrità.

Per risolvere questo problema, assicurati che la funzione chiamata sia dello stesso tipo che era dichiarate in modo statico. Ecco due esempi di CL:

Un altro possibile problema è l'attivazione di CFI in un codice che contiene dati chiamate all'assemblaggio. Poiché il codice assembly non viene digitato, viene generato non corrispondente.

Per risolvere il problema, crea wrapper di codice nativo per ogni chiamata di montaggio e assegna i wrapper hanno la stessa firma di funzione del poiner di chiamata. Il wrapper può quindi chiamare direttamente il codice Assembly. Poiché i rami diretti non sono instrumentati CFI (non possono essere rivisitate in fase di runtime, quindi non rappresentano un rischio per la sicurezza), il problema sarà risolto.

Se sono presenti troppe funzioni di assemblaggio e non possono essere tutte corrette, puoi e inserire nella blacklist tutte le funzioni che contengono chiamate indirette all'assemblaggio. Questo è non è consigliato in quanto disattiva i controlli CFI su queste funzioni, aprendo così superficie di attacco.

Disattivazione di CFI

Non abbiamo osservato alcun overhead del rendimento, quindi non dovrebbe essere necessario disattivare CFI. Tuttavia, se riscontri un impatto sull'utente, puoi disattivare selettivamente il CFI per singole funzioni o file di origine fornendo un file di lista nera di sanitizer al momento della compilazione. La lista nera indica al compilatore di disabilitare CFI della strumentazione in posizioni specificate.

Il sistema di compilazione di Android fornisce supporto per le liste nere per componente (consentendo è possibile scegliere file sorgente o singole funzioni che non riceveranno CFI strumentazione) sia per Make sia per Presto. Per ulteriori dettagli sul formato di un il file della lista nera, consulta l'upstream Documenti clan.

Convalida

Al momento, non esistono test CTS specifici per CFI. Assicurati invece I test CTS vengono superati con o senza CFI abilitato per verificare che non ci siano conseguenze per il CFI del dispositivo.