Google is committed to advancing racial equity for Black communities. See how.
Cette page a été traduite par l'API Cloud Translation.
Switch to English

Intégrité du flux de contrôle

En 2016, environ 86% de toutes les vulnérabilités sur Android sont liées à la sécurité de la mémoire. La plupart des vulnérabilités sont exploitées par des attaquants modifiant le flux de contrôle normal d'une application pour effectuer des activités malveillantes arbitraires avec tous les privilèges de l'application exploitée. L'intégrité du flux de contrôle (CFI) est un mécanisme de sécurité qui interdit les modifications du graphe de flux de contrôle d'origine d'un binaire compilé, ce qui rend considérablement plus difficile l'exécution de telles attaques.

Dans Android 8.1, nous avons activé l'implémentation de CFI par LLVM dans la pile multimédia. Dans Android 9, nous avons activé CFI dans plus de composants ainsi que dans le noyau. Le système CFI est activé par défaut mais vous devez activer le noyau CFI.

Le CFI de LLVM nécessite une compilation avec Link-Time Optimization (LTO) . LTO préserve la représentation bitcode LLVM des fichiers objets jusqu'au moment de la liaison, ce qui permet au compilateur de mieux raisonner sur les optimisations qui peuvent être effectuées. L'activation de LTO réduit la taille du binaire final et améliore les performances, mais augmente le temps de compilation. Lors des tests sur Android, la combinaison de LTO et CFI entraîne une surcharge négligeable en termes de taille et de performances du code; dans quelques cas, les deux se sont améliorés.

Pour plus de détails techniques sur CFI et la manière dont les autres contrôles de contrôle avant sont gérés, consultez la documentation de conception LLVM .

Exemples et source

CFI est fourni par le compilateur et ajoute une instrumentation dans le binaire pendant la compilation. Nous soutenons CFI dans la chaîne d'outils Clang et le système de construction Android dans AOSP.

CFI est activé par défaut pour les périphériques Arm64 pour l'ensemble de composants dans /platform/build/target/product/cfi-common.mk . Il est également directement activé dans un ensemble de fichiers makefiles / blueprint de composants multimédias, tels que /platform/frameworks/av/media/libmedia/Android.bp et /platform/frameworks/av/cmds/stagefright/Android.mk .

Système de mise en œuvre CFI

CFI est activé par défaut si vous utilisez Clang et le système de construction Android. Parce que CFI contribue à la sécurité des utilisateurs d'Android, vous ne devez pas le désactiver.

En fait, nous vous encourageons vivement à activer CFI pour des composants supplémentaires. Les candidats idéaux sont le code natif privilégié ou le code natif qui traite les entrées utilisateur non approuvées. Si vous utilisez clang et le système de construction Android, vous pouvez activer CFI dans de nouveaux composants en ajoutant quelques lignes à vos fichiers makefiles ou blueprint.

Soutenir CFI dans les makefiles

Pour activer CFI dans un fichier de /platform/frameworks/av/cmds/stagefright/Android.mk , tel que /platform/frameworks/av/cmds/stagefright/Android.mk , ajoutez:

LOCAL_SANITIZE := cfi
# Optional features
LOCAL_SANITIZE_DIAG := cfi
LOCAL_SANITIZE_BLACKLIST := cfi_blacklist.txt
  • LOCAL_SANITIZE spécifie CFI comme désinfectant pendant la génération.
  • LOCAL_SANITIZE_DIAG active le mode de diagnostic pour CFI. Le mode de diagnostic imprime des informations de débogage supplémentaires dans logcat pendant les plantages, ce qui est utile lors du développement et du test de vos builds. Assurez-vous cependant de supprimer le mode de diagnostic sur les versions de production.
  • LOCAL_SANITIZE_BLACKLIST permet aux composants de désactiver sélectivement l'instrumentation CFI pour des fonctions individuelles ou des fichiers source. Vous pouvez utiliser une liste noire en dernier recours pour résoudre les problèmes rencontrés par les utilisateurs qui pourraient autrement exister. Pour plus de détails, voir Désactivation de CFI .

Soutenir CFI dans les fichiers de plans

Pour activer CFI dans un fichier blueprint, tel que /platform/frameworks/av/media/libmedia/Android.bp , ajoutez:

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

Dépannage

Si vous activez CFI dans de nouveaux composants, vous pouvez rencontrer quelques problèmes avec des erreurs d'incompatibilité de type de fonction et des erreurs d'incompatibilité de type de code d'assemblage .

Des erreurs d'incompatibilité de type de fonction se produisent car CFI restreint les appels indirects à sauter uniquement aux fonctions qui ont le même type dynamique que le type statique utilisé dans l'appel. CFI limite les appels de fonctions membres virtuels et non virtuels à sauter uniquement aux objets qui sont une classe dérivée du type statique de l'objet utilisé pour effectuer l'appel. Cela signifie que lorsque vous avez un code qui enfreint l'une ou l'autre de ces hypothèses, l'instrumentation que CFI ajoute sera abandonnée. Par exemple, la trace de pile montre un SIGABRT et logcat contient une ligne sur l'intégrité du flux de contrôle trouvant une incompatibilité.

Pour résoudre ce problème, assurez-vous que la fonction appelée a le même type que celui qui a été déclaré statiquement. Voici deux exemples de CL:

Un autre problème possible consiste à essayer d'activer CFI dans le code qui contient des appels indirects à l'assembly. Étant donné que le code d'assembly n'est pas tapé, cela entraîne une incompatibilité de type.

Pour résoudre ce problème, créez des wrappers de code natif pour chaque appel d'assembly et donnez aux wrappers la même signature de fonction que le pointeur appelant. Le wrapper peut alors appeler directement le code d'assembly. Étant donné que les succursales directes ne sont pas instrumentées par CFI (elles ne peuvent pas être rejointes au moment de l'exécution et ne présentent donc pas de risque pour la sécurité), cela résoudra le problème.

S'il y a trop de fonctions d'assemblage et qu'elles ne peuvent pas toutes être corrigées, vous pouvez également mettre sur liste noire toutes les fonctions qui contiennent des appels indirects à l'assembly. Ceci n'est pas recommandé car cela désactive les contrôles CFI sur ces fonctions, ouvrant ainsi la surface d'attaque.

Désactiver CFI

Nous n'avons observé aucune surcharge de performance, vous ne devriez donc pas avoir besoin de désactiver CFI. Toutefois, s'il y a un impact sur l'utilisateur, vous pouvez désactiver de manière sélective CFI pour des fonctions individuelles ou des fichiers source en fournissant un fichier de liste noire de désinfectant au moment de la compilation. La liste noire indique au compilateur de désactiver l'instrumentation CFI dans les emplacements spécifiés.

Le système de construction Android prend en charge les listes noires par composant (vous permettant de choisir des fichiers source ou des fonctions individuelles qui ne recevront pas d'instrumentation CFI) pour Make et Soong. Pour plus de détails sur le format d'un fichier de liste noire, consultez la documentation Clang en amont .

Validation

Actuellement, il n'y a pas de test CTS spécifiquement pour CFI. Assurez-vous plutôt que les tests CTS réussissent avec ou sans CFI activé pour vérifier que CFI n'affecte pas l'appareil.