Scudo est un outil d'allocation de mémoire dynamique en mode utilisateur, ou allocateur de tas, conçu pour être résilient face aux failles liées au tas (telles que l'erreur de débordement de tampon basée sur le tas, l'utilisation après libération et la double libération) tout en conservant les performances. Il fournit les primitives d'allocation et de désallocation standard en C (comme malloc et free), ainsi que les primitives C++ (comme new et delete).
Scudo est davantage une atténuation qu'un véritable détecteur d'erreurs de mémoire, comme AddressSanitizer (ASan).
Depuis la sortie d'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. Le processus est interrompu si une corruption ou un comportement suspect est détecté dans le tas.
Scudo est un projet Open Source qui fait partie du projet compiler-rt de LLVM. La documentation est disponible sur https://llvm.org/docs/ScudoHardenedAllocator.html. L'environnement d'exécution Scudo est fourni avec la chaîne d'outils Android. La prise en charge a été ajoutée à Soong et Make pour permettre d'activer facilement l'outil d'allocation dans un binaire.
Vous pouvez activer ou désactiver une atténuation supplémentaire dans l'outil d'allocation à l'aide des options décrites ci-dessous.
Personnalisation
Certains paramètres de l'outil d'allocation peuvent être définis par processus de différentes manières:
- De manière statique: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 | Par défaut, 64 bits | Par défaut 32 bits | Description |
---|---|---|---|
QuarantineSizeKb |
256 |
64 |
Taille (en Ko) de la mise en quarantaine utilisée pour retarder la désallocation réelle des blocs. Une valeur plus faible 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 cette valeur et ThreadLocalQuarantineSizeKb sur zéro désactive complètement la mise en quarantaine. |
QuarantineChunksUpToSize |
2048 |
512 |
Taille (en octets) maximale des segments pouvant être mis en quarantaine. |
ThreadLocalQuarantineSizeKb |
64 |
16 |
Taille (en Ko) de l'utilisation du cache par thread pour décharger la mise en quarantaine globale.
Une valeur plus faible peut réduire l'utilisation de la mémoire, mais elle peut augmenter les conflits sur la mise en quarantaine globale. Définir cette valeur et QuarantineSizeKb sur zéro désactive complètement la mise en quarantaine. |
DeallocationTypeMismatch |
false |
false |
Active la création de rapports d'erreur sur malloc/delete, new/free et new/delete[]. |
DeleteSizeMismatch |
true |
true |
Active le signalement d'erreurs en cas de non-concordance entre les tailles de création et de suppression. |
ZeroContents |
false |
false |
Active les contenus de blocs nuls lors de l'allocation et de la désallocation. |
allocator_may_return_null |
false |
false |
Indique que l'outil d'allocation peut renvoyer la valeur nulle lorsqu'une erreur récupérable se produit, au lieu de mettre fin au processus. |
hard_rss_limit_mb |
0 |
0 |
Lorsque la mémoire RSS du processus atteint cette limite, le processus se termine. |
soft_rss_limit_mb |
0 |
0 |
Lorsque la RSS du processus atteint cette limite, les allocations supplémentaires échouent ou renvoient null (selon la valeur de allocator_may_return_null ), jusqu'à ce que la RSS diminue pour permettre de nouvelles allocations. |
allocator_release_to_os_interval_ms |
N/A | 5000 |
Ne concerne qu'un alloueur 64 bits. Si défini, tente de libérer la mémoire inutilisée à l'OS, mais pas plus souvent que cet intervalle (en millisecondes). Si la valeur est négative, la mémoire n'est pas libérée pour l'OS. |
abort_on_error |
true |
true |
Si ce paramètre est défini, l'outil appelle abort() au lieu de _exit() après avoir imprimé le message d'erreur. |
Validation
Pour le moment, il n'existe aucun test CTS spécifique à Scudo. Assurez-vous plutôt que les tests CTS réussissent avec ou sans Scudo activé pour un binaire donné afin de vérifier qu'il n'a aucun impact sur l'appareil.
Dépannage
Si un problème non récupérable est détecté, l'outil d'allocation affiche un message d'erreur au descripteur d'erreur standard, puis arrête le processus.
Les traces de pile qui entraînent l'arrêt sont ajoutées au journal système.
La sortie commence généralement par Scudo ERROR:
, suivie d'un bref résumé du problème, ainsi que de tout pointeur.
Vous trouverez ci-dessous la liste des messages d'erreur actuels et leurs causes potentielles:
corrupted chunk header
: la validation de la somme de contrôle de l'en-tête de bloc a échoué. Cela est probablement dû à l'une des deux raisons suivantes: l'en-tête a été écrasé (partiellement ou totalement), ou le pointeur transmis à la fonction n'est pas un bloc.race on chunk header
: Deux threads différents tentent de manipuler le même en-tête en même temps. Il s'agit généralement d'un symptôme de conflit ou d'un manque général de verrouillage lors de l'exécution d'opérations sur ce bloc.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. Une double libération est la cause la plus courante de cette erreur.misaligned pointer
: les exigences d'alignement de base sont strictement appliquées: 8 octets sur les plates-formes 32 bits et 16 octets sur les plates-formes 64 bits. Si un pointeur transmis à nos fonctions ne correspond pas à ces valeurs, le pointeur transmis à l'une des fonctions est mal aligné.allocation type mismatch
: lorsque cette option est activée, une fonction de désallocation appelée sur un bloc doit correspondre au type de fonction qui a été appelé pour l'allouer. Ce type de non-concordance peut entraîner 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 incohérence entre la taille transmise lors de la désallocation d'un bloc et la taille 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
: le nombre maximal de flux RSS spécifié de manière facultative a été dépassé.
Si vous déboguez un plantage dans l'OS lui-même, vous pouvez utiliser un build d'OS HWASan. Si vous déboguez un plantage dans une application, vous pouvez également utiliser un build d'application HWASan.