Scudo

Scudo est un allocateur de mémoire dynamique en mode utilisateur, ou allocateur de tas , conçu pour être résilient contre les vulnérabilités liées au tas (telles que le débordement de tampon basé sur le tas , l'utilisation après free et le double free ) tout en maintenant les performances. Il fournit les primitives standard d'allocation et de désallocation C (telles que malloc et free), ainsi que les primitives C++ (telles que new et delete).

Scudo est plus une atténuation qu'un détecteur d'erreurs de mémoire à part entière comme AddressSanitizer (ASan) .

Depuis la version Android 11, scudo est utilisé pour tout le code natif (sauf sur les appareils à faible mémoire, où jemalloc est toujours utilisé). Au moment de l'exécution, toutes les allocations et désallocations de tas natives sont gérées par Scudo pour tous les exécutables et leurs dépendances de bibliothèque, et le processus est abandonné si une corruption ou un comportement suspect est détecté dans le tas.

Scudo est open source et fait partie du projet compiler-rt de LLVM. La documentation est disponible sur https://llvm.org/docs/ScudoHardenedAllocator.html . Le runtime Scudo est livré dans le cadre de la chaîne d'outils Android et la prise en charge a été ajoutée à Soong et Make pour permettre une activation facile de l'allocateur dans un binaire.

Vous pouvez activer ou désactiver une atténuation supplémentaire dans l'allocateur à l'aide des options décrites ci-dessous.

Personnalisation

Certains paramètres de l'allocateur peuvent être définis processus par processus de plusieurs manières :

  • Statiquement : définissez une fonction __scudo_default_options dans le programme qui renvoie la chaîne d'options à analyser. Cette fonction doit avoir le prototype suivant : extern "C" const char *__scudo_default_options() .
  • Dynamiquement : utilisez la variable d'environnement SCUDO_OPTIONS contenant la chaîne d'options à analyser. Les options définies de cette manière remplacent toute définition effectuée via __scudo_default_options .

Les options suivantes sont disponibles.

Option 64 bits par défaut 32 bits par défaut Description
QuarantineSizeKb 256 64 La taille (en Ko) de la quarantaine utilisée pour retarder la désallocation réelle des fragments. Une valeur inférieure peut réduire l'utilisation de la mémoire mais diminuer l'efficacité de l'atténuation ; une valeur négative revient aux valeurs par défaut. Définir à la fois ceci et ThreadLocalQuarantineSizeKb sur zéro désactive complètement la quarantaine.
QuarantineChunksUpToSize 2048 512 Taille (en octets) jusqu'à laquelle les fragments peuvent être mis en quarantaine.
ThreadLocalQuarantineSizeKb 64 16 Taille (en Ko) du cache par thread utilisé pour décharger la quarantaine globale. Une valeur inférieure peut réduire l'utilisation de la mémoire mais peut augmenter les conflits sur la quarantaine globale. La définition de ceci et QuarantineSizeKb sur zéro désactive entièrement la quarantaine.
DeallocationTypeMismatch false false Active le rapport d'erreurs sur malloc/delete, new/free, new/delete[]
DeleteSizeMismatch true true Active le rapport d'erreurs en cas de non-concordance entre les tailles de nouveau et de suppression.
ZeroContents false false Active le contenu zéro bloc lors de l’allocation et de la désallocation.
allocator_may_return_null false false Spécifie que l'allocateur peut renvoyer null lorsqu'une erreur récupérable se produit, au lieu de mettre fin au processus.
hard_rss_limit_mb 0 0 Lorsque le RSS du processus atteint cette limite, le processus se termine.
soft_rss_limit_mb 0 0 Lorsque le RSS du processus atteint cette limite, les allocations ultérieures échouent ou renvoient null (en fonction de la valeur de allocator_may_return_null ), jusqu'à ce que le RSS redescende pour permettre de nouvelles allocations.
allocator_release_to_os_interval_ms N / A 5000 Affecte uniquement un allocateur 64 bits. S'il est défini, tente de libérer la mémoire inutilisée vers le système d'exploitation, mais pas plus souvent que cet intervalle (en millisecondes). Si la valeur est négative, la mémoire n'est pas libérée vers le système d'exploitation.
abort_on_error true true S'il est défini, l'outil appelle abort() au lieu de _exit() après l'impression du message d'erreur.

Validation

Actuellement, il n’existe aucun test CTS spécifiquement pour Scudo. Au lieu de cela, assurez-vous que les tests CTS réussissent avec ou sans Scudo activé pour un binaire donné afin de vérifier qu'il n'a pas d'impact sur le périphérique.

Dépannage

Si un problème non récupérable est détecté, l'allocateur affiche un message d'erreur au descripteur d'erreur standard, puis met fin au processus. Les traces de pile menant à l'arrêt sont ajoutées dans le journal système. La sortie commence généralement par Scudo ERROR: suivi d'un bref résumé du problème ainsi que d'éventuels pointeurs.

Voici une liste des messages d'erreur actuels et de leurs causes potentielles :

  • corrupted chunk header : la vérification de la somme de contrôle de l'en-tête du bloc a échoué. Cela est probablement dû à l'une des deux choses suivantes : l'en-tête a été écrasé (partiellement ou totalement) ou le pointeur passé à la fonction n'est pas un morceau.
  • race on chunk header : deux threads différents tentent de manipuler le même en-tête en même temps. Ceci est généralement symptomatique d'une condition de concurrence critique ou d'un manque général de verrouillage lors de l'exécution d'opérations sur ce morceau.
  • invalid chunk state : le bloc n'est pas dans l'état attendu pour une opération donnée, par exemple, il n'est pas alloué lorsque vous essayez de le libérer, ou il n'est pas mis en quarantaine lorsque vous essayez de le recycler. Un double gratuit est la raison typique de cette erreur.
  • misaligned pointer : les exigences d'alignement de base sont fortement appliquées : 8 octets sur les plates-formes 32 bits et 16 octets sur les plates-formes 64 bits. Si un pointeur passé à nos fonctions ne correspond pas à celles-ci, le pointeur passé à l'une des fonctions n'est pas aligné.
  • allocation type mismatch : Lorsque cette option est activée, une fonction de désallocation appelée sur un chunk doit correspondre au type de fonction qui a été appelée pour l'allouer. Ce type de discordance peut introduire des problèmes de sécurité.
  • invalid sized delete : lorsque l'opérateur de suppression de taille C++ 14 est utilisé et que la vérification facultative est activée, il existe une incompatibilité entre la taille qui a été transmise lors de la désallocation d'un morceau et la taille qui a été demandée lors de son allocation. Il s'agit généralement d'un problème de compilateur ou d'une confusion de type sur l'objet en cours de désallocation.
  • RSS limit exhausted : La limite RSS maximale spécifiée en option a été dépassée.

Si vous déboguez un crash dans le système d'exploitation lui-même, vous pouvez utiliser une version du système d'exploitation HWASan . Si vous déboguez un crash dans une application, il est également possible d'utiliser une version d'application HWASan .