AdresseSanitizer

AddressSanitizer (ASan) est un outil rapide basé sur un compilateur pour détecter les bogues de mémoire dans le code natif.

ASan détecte :

  • Débordement/sous-débordement du tampon de pile et de tas
  • Utilisation en tas après la gratuité
  • Utilisation de la pile en dehors de la portée
  • Double gratuit/sauvage gratuit

ASan fonctionne sur ARM 32 bits et 64 bits, plus x86 et x86-64. La surcharge CPU d'ASan est d'environ 2x, la surcharge de taille de code est comprise entre 50 % et 2x, et une surcharge mémoire importante (en fonction de vos modèles d'allocation, mais de l'ordre de 2x).

Les applications 10 et la branche principale de PSBA sur support AArch64 Asan accélération matérielle (HWASan) , un outil similaire avec des frais généraux de RAM plus faible et une plus large gamme d'insectes détectés. HWASan détecte l'utilisation de la pile après le retour, en plus des bogues détectés par ASan.

HWASan a une surcharge de CPU et de taille de code similaire, mais une surcharge de RAM beaucoup plus petite (15%). HWASan est non déterministe. Il n'y a que 256 valeurs de balises possibles, il y a donc une probabilité plate de 0,4% de manquer un bogue. HWASan n'a pas les zones rouges de taille limitée d'ASan pour détecter les débordements et la quarantaine à capacité limitée pour détecter l'utilisation après l'absence, donc peu importe pour HWASan la taille du débordement ou la durée depuis laquelle la mémoire a été désallouée. Cela rend HWASan meilleur que ASan. Vous pouvez en savoir plus sur la conception de HWASan ou sur l'utilisation de HWASan sur Android .

ASan détecte les débordements de pile/globaux en plus des débordements de tas, et est rapide avec une surcharge de mémoire minimale.

Ce document décrit comment créer et exécuter des parties/toutes d'Android avec ASan. Si vous construisez un SDK / app NDK avec Asan, voir Adresse Sanitizer à la place.

Désinfection des exécutables individuels avec ASan

Ajouter LOCAL_SANITIZE:=address ou sanitize: { address: true } à la règle de construction de l'exécutable. Vous pouvez rechercher dans le code des exemples existants ou pour trouver les autres désinfectants disponibles.

Lorsqu'un bug est détecté, Asan imprime un rapport détaillé à la fois la sortie standard et logcat puis bloque le processus.

Désinfection des bibliothèques partagées avec ASan

En raison du fonctionnement d'ASan, une bibliothèque construite avec ASan ne peut être utilisée que par un exécutable construit avec ASan.

Pour nettoyer une bibliothèque partagée qui est utilisée dans plusieurs exécutables, qui ne sont pas tous construits avec ASan, vous avez besoin de deux copies de la bibliothèque. La méthode recommandée pour le faire est d'ajouter ce qui suit à Android.mk pour le module en question:

LOCAL_SANITIZE:=address
LOCAL_MODULE_RELATIVE_PATH := asan

Cela met la bibliothèque dans /system/lib/asan au lieu de /system/lib . Ensuite, lancez votre exécutable avec :

LD_LIBRARY_PATH=/system/lib/asan

Pour daemons système, ajouter ce qui suit à la section appropriée de /init.rc ou /init.$device$.rc .

setenv LD_LIBRARY_PATH /system/lib/asan

Vérifiez que le processus utilise les bibliothèques de /system/lib/asan lorsqu'il est présent en lecture /proc/$PID/maps . Si ce n'est pas le cas, vous devrez peut-être désactiver SELinux :

adb root
adb shell setenforce 0
# restart the process with adb shell kill $PID
# if it is a system service, or may be adb shell stop; adb shell start.

Meilleures traces de pile

ASan utilise un dérouleur rapide basé sur un pointeur de trame pour enregistrer une trace de pile pour chaque événement d'allocation et de désallocation de mémoire dans le programme. La plupart d'Android est construit sans pointeurs de trame. En conséquence, vous n'obtenez souvent qu'une ou deux images significatives. Pour résoudre ce problème, reconstruisez la bibliothèque avec ASan (recommandé !), ou avec :

LOCAL_CFLAGS:=-fno-omit-frame-pointer
LOCAL_ARM_MODE:=arm

Ou mettre ASAN_OPTIONS=fast_unwind_on_malloc=0 dans l'environnement de processus. Ce dernier peut être très gourmand en CPU, selon la charge.

Symbolisation

Initialement, les rapports ASan contiennent des références aux décalages dans les binaires et les bibliothèques partagées. Il existe deux manières d'obtenir des informations sur le fichier source et la ligne :

  • Assurez -vous que le llvm-symbolizer binaire est présent dans /system/bin . llvm-symbolizer est construit à partir de sources third_party/llvm/tools/llvm-symbolizer .
  • Filtrer le rapport par le external/compiler-rt/lib/asan/scripts/symbolize.py script.

La seconde approche peut fournir plus de données (qui est, file:line emplacements) en raison de la disponibilité des bibliothèques symbolisés sur l'hôte.

ASan dans les applications

ASan ne peut pas voir dans le code Java, mais il peut détecter les bogues dans les bibliothèques JNI. Pour cela, vous devez construire l'exécutable avec Asan, qui dans ce cas est /system/bin/app_process( 32|64 ) . Cela permet à ASan dans toutes les applications de l'appareil en même temps, ce qui est une charge lourde, mais un appareil avec 2 Go de RAM devrait être capable de gérer cela.

Ajouter LOCAL_SANITIZE:=address à la app_process règle de construction dans les frameworks/base/cmds/app_process . Ignorer la app_process__asan cible dans le même fichier pour l' instant (si elle est toujours là au moment où vous lirez ces lignes ).

Modifier le service zygote section appropriée du system/core/rootdir/init.zygote( 32|64 ).rc fichier à ajouter les lignes suivantes de la séquence de lignes en retrait contenant class main , également en retrait par la même quantité:

    setenv LD_LIBRARY_PATH /system/lib/asan:/system/lib
    setenv ASAN_OPTIONS allow_user_segv_handler=true

Build, adb sync, fastboot flash boot et reboot.

Utilisation de la propriété wrap

L'approche de la section précédente place ASan dans chaque application du système (en fait, dans chaque descendant du processus Zygote). Il est possible de n'exécuter qu'une (ou plusieurs) applications avec ASan, en échangeant une surcharge de mémoire contre un démarrage plus lent de l'application.

Cela peut être fait en démarrant votre application avec l' wrap. biens. L'exemple suivant exécute l'application Gmail sous ASan :

adb root
adb shell setenforce 0  # disable SELinux
adb shell setprop wrap.com.google.android.gm "asanwrapper"

Dans ce contexte, asanwrapper réécritures /system/bin/app_process au /system/bin/asan/app_process , qui est construit avec Asan. Il ajoute /system/lib/asan au début du chemin de recherche de bibliothèque dynamique. Cette bibliothèques façon Asan-instrumentée de /system/lib/asan sont préférés aux bibliothèques normales dans /system/lib lors de l' exécution avec asanwrapper .

Si un bogue est détecté, l'application se bloque et le rapport est imprimé dans le journal.

SANITIZE_TARGET

Android 7.0 et versions ultérieures incluent la prise en charge de la création simultanée de l'intégralité de la plate-forme Android avec ASan. (Si vous créez une version supérieure à Android 9, HWASan est un meilleur choix.)

Exécutez les commandes suivantes dans la même arborescence de génération.

make -j42
SANITIZE_TARGET=address make -j42

Dans ce mode, userdata.img contient des bibliothèques supplémentaires et doit être flashé à l'appareil aussi bien. Utilisez la ligne de commande suivante :

fastboot flash userdata && fastboot flashall

Cela construit deux ensembles de bibliothèques partagées: normal dans /system/lib (la première invocation de marque) et Asan-instrumenté /data/asan/lib (second make invocation). Les exécutables du deuxième build écrasent ceux du premier build. Executables Asan-instrumentés obtenir un chemin de recherche autre bibliothèque qui comprend /data/asan/lib avant /system/lib grâce à l'utilisation du /system/bin/linker_asan dans PT_INTERP .

Le système de construction aplatit les répertoires d'objets intermédiaires lorsque la $SANITIZE_TARGET valeur a changé. Ces forces de recompiler toutes les cibles , tout en préservant les binaires installés sous /system/lib .

Certaines cibles ne peuvent pas être construites avec ASan :

  • Exécutables liés statiquement
  • LOCAL_CLANG:=false cibles
  • LOCAL_SANITIZE:=false ne sont pas ASan'd pour SANITIZE_TARGET=address

Executables comme ceux - ci ne sont pas pris dans la SANITIZE_TARGET build, et la version de la première invocation de marque est laissé dans /system/bin .

Les bibliothèques comme celle-ci sont construites sans ASan. Ils peuvent contenir du code ASan des bibliothèques statiques dont ils dépendent.

Documentation à l'appui