O Google tem o compromisso de promover a igualdade racial para as comunidades negras. Saiba como.
Esta página foi traduzida pela API Cloud Translation.
Switch to English

Integridade do Fluxo de Controle

Em 2016, cerca de 86% de todas as vulnerabilidades no Android estão relacionadas à segurança da memória. A maioria das vulnerabilidades é explorada por invasores que alteram o fluxo de controle normal de um aplicativo para realizar atividades maliciosas arbitrárias com todos os privilégios do aplicativo explorado. 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, tornando significativamente mais difícil realizar tais ataques.

No Android 8.1, habilitamos a implementação de CFI do LLVM na pilha de mídia. No Android 9, habilitamos 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 a compilação com Link-Time Optimization (LTO) . O LTO preserva a representação do código de bits do LLVM de arquivos de objeto até o tempo de link, o que permite ao compilador raciocinar melhor sobre quais otimizações podem ser realizadas. Habilitar LTO reduz o tamanho do binário final e melhora o desempenho, mas aumenta o tempo de compilação. Em testes no Android, a combinação de LTO e CFI resulta em sobrecarga insignificante para o tamanho do código e desempenho; 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 de design do LLVM .

Exemplos e fonte

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

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

Implementando sistema CFI

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

Na verdade, recomendamos que você habilite o CFI para componentes adicionais. Os candidatos ideais são código nativo privilegiado ou código nativo que processa entrada de usuário não confiável. Se você estiver usando o clang e o sistema de construção Android, poderá habilitar o CFI em novos componentes adicionando algumas linhas aos seus makefiles ou arquivos de blueprint.

Suportando CFI em makefiles

Para habilitar 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 sanitizer 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 travamentos, o que é útil ao desenvolver e testar suas compilações. Certifique-se de remover o modo de diagnóstico em compilações de produção, no entanto.
  • LOCAL_SANITIZE_BLACKLIST permite que os componentes desabilitem 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 enfrentados pelo usuário que possam existir. Para obter mais detalhes, consulte Desativando CFI .

Apoiar 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 habilitando 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 as chamadas indiretas para pular apenas para as funções que têm o mesmo tipo dinâmico do tipo estático usado na chamada. CFI restringe 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 qualquer uma dessas suposições, a instrumentação que o CFI adiciona será interrompida. Por exemplo, o rastreamento de pilha mostra um SIGABRT e o logcat contém uma linha sobre a integridade do fluxo de controle encontrando uma incompatibilidade.

Para corrigir isso, certifique-se de que a função chamada tenha 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 ao assembly. Como o código assembly não é digitado, isso resulta em uma incompatibilidade de tipo.

Para corrigir isso, crie wrappers de código nativo para cada chamada de assembly e dê aos wrappers a mesma assinatura de função do apontador de chamada. O wrapper pode então chamar diretamente o código do assembly. Como os branches diretos não são instrumentados pelo CFI (eles não podem ser refeitos em tempo de execução e, portanto, não representam um risco de segurança), isso resolverá o problema.

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

Desativando CFI

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

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

Validação

Atualmente, não há nenhum teste CTS específico para CFI. Em vez disso, certifique-se de que os testes CTS sejam aprovados com ou sem o CFI habilitado para verificar se o CFI não está afetando o dispositivo.