O Google está comprometido em promover a equidade racial para as comunidades negras. Veja como.
Esta página foi traduzida pela API Cloud Translation.
Switch to English

Control Flow Integrity

A partir de 2016, cerca de 86% de todas as vulnerabilidades no Android estão relacionadas à segurança da memória. A maioria das vulnerabilidades é explorada pelos invasores, alterando o fluxo de controle normal de um aplicativo para executar atividades maliciosas arbitrárias com todos os privilégios do aplicativo explorado. A integridade do fluxo de controle (CFI) é um mecanismo de segurança que não permite alterações no gráfico de fluxo de controle original de um binário compilado, dificultando significativamente a execução desses ataques.

No Android 8.1, ativamos a implementação do CFI do LLVM na pilha de mídia. No Android 9, ativamos o CFI em mais componentes e também no kernel. O CFI do sistema está ativado por padrão, mas você precisa habilitar o CFI do kernel.

O CFI do LLVM requer compilação com o Link-Time Optimization (LTO) . O LTO preserva a representação do código de bit LLVM dos arquivos de objeto até o tempo do link, o que permite ao compilador raciocinar melhor sobre quais otimizações podem ser executadas. A ativação do LTO reduz o tamanho do binário final e melhora o desempenho, mas aumenta o tempo de compilação. Nos testes no Android, a combinação de LTO e CFI resulta em sobrecarga insignificante para tamanho e desempenho do código; em alguns casos, ambos melhoraram.

Para obter mais detalhes técnicos sobre o CFI e como outras verificações de controle de avanço são tratadas, consulte a documentação do projeto do LLVM .

Exemplos e fonte

O CFI é fornecido pelo compilador e adiciona instrumentação ao binário durante o tempo de compilação. Apoiamos o CFI na cadeia de ferramentas Clang e o sistema de compilação Android no AOSP.

O CFI é ativado por padrão para dispositivos Arm64 para o conjunto de componentes em /platform/build/target/product/cfi-common.mk . Ele também é ativado diretamente em um conjunto de arquivos makefiles / blueprint dos componentes de mídia, como /platform/frameworks/av/media/libmedia/Android.bp e /platform/frameworks/av/cmds/stagefright/Android.mk .

Implementando o CFI do sistema

O CFI é ativado por padrão se você usar o Clang e o sistema de compilação Android. Como o CFI ajuda a manter os usuários do Android seguros, você não deve desativá-lo.

De fato, recomendamos que você ative o CFI para componentes adicionais. Os candidatos ideais são código nativo privilegiado ou código nativo que processa a entrada não confiável do usuário. Se você estiver usando o clang e o sistema de compilação Android, poderá ativar o CFI em novos componentes adicionando algumas linhas aos arquivos de makefiles ou blueprint.

Suporte ao CFI em makefiles

Para habilitar o CFI em um arquivo make, como /platform/frameworks/av/cmds/stagefright/Android.mk , adicione:

LOCAL_SANITIZE := cfi
# Optional features
LOCAL_SANITIZE_DIAG := cfi
LOCAL_SANITIZE_BLACKLIST := cfi_blacklist.txt
  • LOCAL_SANITIZE especifica CFI como o desinfetante durante a construção.
  • LOCAL_SANITIZE_DIAG ativa o modo de diagnóstico para CFI. O modo de diagnóstico imprime informações adicionais de depuração no logcat durante falhas, o que é útil ao desenvolver e testar suas compilações. Certifique-se de remover o modo de diagnóstico nas construções de produção, no entanto.
  • LOCAL_SANITIZE_BLACKLIST permite que componentes desativem seletivamente a instrumentação CFI para funções individuais ou arquivos de origem. Você pode usar uma lista negra como último recurso para corrigir quaisquer problemas que possam surgir do usuário. Para obter mais detalhes, consulte Desabilitando o CFI .

Suporte ao CFI em arquivos de blueprint

Para habilitar o CFI em um arquivo blueprint, como /platform/frameworks/av/media/libmedia/Android.bp , adicione:

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

Solução de problemas

Se você estiver ativando o CFI em novos componentes, poderá encontrar alguns problemas com erros de incompatibilidade de tipo de função e erros de incompatibilidade de tipo de código de montagem .

Os erros de incompatibilidade de tipo de função ocorrem porque o CFI restringe chamadas indiretas para saltar apenas para funções que possuem o mesmo tipo dinâmico que o tipo estático usado na chamada. O CFI restringe as chamadas de função de membro virtual e não virtual para saltar apenas para objetos que são uma classe derivada do tipo estático do objeto usado para fazer a chamada. Isso significa que, quando você tiver um código que viole uma dessas suposições, a instrumentação adicionada pelo CFI será abortada. Por exemplo, o rastreamento de pilha mostra um SIGABRT e o logcat contém uma linha sobre a integridade do fluxo de controle que encontra uma incompatibilidade.

Para corrigir isso, verifique se a função chamada tem o mesmo tipo que foi declarado estaticamente. Aqui estão dois exemplos de CLs:

Outro possível problema é tentar habilitar o CFI no código que contém chamadas indiretas para montagem. Como o código de montagem não é digitado, isso resulta em uma incompatibilidade de tipo.

Para corrigir isso, crie wrappers de código nativo para cada chamada de montagem e atribua aos wrappers a mesma assinatura de função que o apontador de chamada. O wrapper pode então chamar diretamente o código de montagem. Como as ramificações diretas não são instrumentadas pelo CFI (elas não podem ser apontadas novamente em tempo de execução e, portanto, não representam um risco à segurança), isso corrigirá o problema.

Se houver muitas funções de montagem e elas não puderem ser corrigidas, você também poderá colocar na lista negra todas as funções que contêm chamadas indiretas para montagem. Isso não é recomendado, pois desabilita as verificações do CFI nessas funções, abrindo assim a superfície de ataque.

Desativando o CFI

Como não observamos nenhuma sobrecarga de desempenho, não é necessário desativar o CFI. No entanto, se houver um impacto voltado para o usuário, você pode desativar seletivamente o CFI para funções individuais ou arquivos de origem, fornecendo um arquivo de lista negra do desinfetante no momento da compilação. A lista negra instrui o compilador a desativar a instrumentação CFI em locais especificados.

O sistema de compilação Android fornece suporte para listas negras por componente (permitindo escolher arquivos de origem ou funções individuais que não receberão instrumentação CFI) para Make e Soong. Para mais detalhes sobre o formato de um arquivo de lista negra, consulte os documentos Clang upstream .

Validação

Atualmente, não há teste CTS especificamente para CFI. Em vez disso, verifique se os testes do CTS passam com ou sem o CFI ativado para verificar se o CFI não está afetando o dispositivo.