Scudo est un outil d'allocation de mémoire dynamique en mode utilisateur, ou tas, conçu pour résister aux failles liées aux tas de mémoire (telles que le dépassement de tampon basé sur les tas de mémoire, l'utilisation après libération et le double free) tout en maintenant 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 natif 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 | 64 bits par défaut | 32 bits par défaut | 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 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 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'erreurs sur malloc/delete, new/free, new/delete[] |
DeleteSizeMismatch |
true |
true |
Active le signalement d'erreurs en cas de non-concordance entre les tailles des éléments "new" et "delete". |
ZeroContents |
false |
false |
Active le contenu de zéro bloc 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 le flux 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 cet intervalle est défini, tente de libérer la mémoire inutilisée sur 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 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
Il n'existe actuellement 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 entièrement) ou le pointeur transmis à la fonction n'est pas un fragment.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. Un double libre est la raison typique 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, celui transmis à 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 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 fragment 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.