Arm v9 introduit Arm Memory Tagging Extension (MTE), une implémentation matérielle de la mémoire étiquetée.
À un niveau élevé, MTE marque chaque allocation/désallocation de mémoire avec des métadonnées supplémentaires. Il attribue une balise à un emplacement mémoire, qui peut ensuite être associée à des pointeurs faisant référence à cet emplacement mémoire. Au moment de l'exécution, le processeur vérifie que le pointeur et les balises de métadonnées correspondent à chaque chargement et stockage.
Dans Android 12, l'allocateur de mémoire du noyau et de l'espace utilisateur peut augmenter chaque allocation avec des métadonnées. Cela permet de détecter les bogues d'utilisation après libération et de débordement de tampon, qui sont la source la plus courante de bogues de sécurité de la mémoire dans nos bases de code.
Modes de fonctionnement du MTE
MTE dispose de trois modes de fonctionnement :
- Mode synchrone (SYNC)
- Mode asynchrone (ASYNC)
- Mode asymétrique (ASYMM)
Mode synchrone (SYNC)
Ce mode est optimisé pour l'exactitude de la détection des bogues par rapport aux performances et peut être utilisé comme un outil de détection de bogues précis, lorsqu'une surcharge de performances plus élevée est acceptable. Lorsqu'il est activé, MTE SYNC agit comme une atténuation de sécurité. En cas de non-concordance de balises, le processeur abandonne immédiatement l'exécution et termine le processus avec SIGSEGV
(code SEGV_MTESERR
) et des informations complètes sur l'accès à la mémoire et l'adresse défaillante.
Nous recommandons d'utiliser ce mode lors des tests comme alternative à HWASan/KASAN ou en production lorsque le processus cible représente une surface d'attaque vulnérable. De plus, lorsque le mode ASYNC a indiqué la présence d'un bug, un rapport de bug précis peut être obtenu en utilisant les API d'exécution pour basculer l'exécution en mode SYNC.
Lorsqu'il est exécuté en mode SYNC, l' allocateur Android enregistre les traces de pile pour toutes les allocations et désallocations et les utilise pour fournir de meilleurs rapports d'erreur incluant une explication d'une erreur de mémoire, telle qu'une utilisation après libération ou un dépassement de tampon, et la pile. traces des événements de mémoire pertinents. De tels rapports fournissent plus d'informations contextuelles et facilitent le suivi et la correction des bogues.
Mode asynchrone (ASYNC)
Ce mode est optimisé pour les performances et la précision des rapports de bogues et peut être utilisé comme détection à faible surcharge pour les bogues de sécurité de la mémoire.
En cas de non-concordance de balises, le processeur poursuit l'exécution jusqu'à l'entrée du noyau la plus proche (par exemple, un appel système ou une interruption de minuterie), où il termine le processus avec SIGSEGV
(code SEGV_MTEAERR
) sans enregistrer l'adresse défaillante ni l'accès à la mémoire.
Nous recommandons d'utiliser ce mode en production sur des bases de code bien testées où la densité des bogues de sécurité mémoire est connue pour être faible, ce qui est obtenu en utilisant le mode SYNC pendant les tests.
Mode asymétrique (ASYMM)
Une fonctionnalité supplémentaire dans Arm v8.7-A, le mode MTE asymétrique permet une vérification synchrone des lectures de mémoire et une vérification asynchrone des écritures de mémoire, avec des performances similaires à celles du mode ASYNC. Dans la plupart des situations, ce mode constitue une amélioration par rapport au mode ASYNC et nous recommandons de l'utiliser à la place d'ASYNC chaque fois qu'il est disponible.
Pour cette raison, aucune des API décrites ci-dessous ne mentionne le mode Asymétrique. Au lieu de cela, le système d'exploitation peut être configuré pour toujours utiliser le mode asymétrique lorsque le mode asynchrone est demandé. Veuillez vous référer à la section « Configuration du niveau MTE préféré spécifique au processeur » pour plus d'informations.
MTE dans l'espace utilisateur
Les sections suivantes décrivent comment MTE peut être activé pour les processus et applications système. MTE est désactivé par défaut, sauf si l'une des options ci-dessous est définie pour un processus particulier (voir pour quels composants MTE est activé ci-dessous ).
Activation de MTE à l'aide du système de build
En tant que propriété à l'échelle du processus, MTE est contrôlée par le paramètre de temps de construction de l'exécutable principal. Les options suivantes permettent de modifier ce paramètre pour des exécutables individuels ou pour des sous-répertoires entiers de l'arborescence source. Le paramètre est ignoré sur les bibliothèques ou sur toute cible qui n'est ni exécutable ni test.
1. Activation de MTE dans Android.bp
( exemple ), pour un projet particulier :
Mode MTE | Paramètre |
---|---|
MTE asynchrone | sanitize: { memtag_heap: true, } |
MTE synchrone | sanitize: { memtag_heap: true, diag: { memtag_heap: true, }, } |
ou dans Android.mk:
Mode MTE | Paramètre |
---|---|
Asynchronous MTE | LOCAL_SANITIZE := memtag_heap |
Synchronous MTE | LOCAL_SANITIZE := memtag_heap LOCAL_SANITIZE_DIAG := memtag_heap |
2. Activation de MTE sur un sous-répertoire de l'arborescence source à l'aide d'une variable de produit :
Mode MTE | Inclure la liste | Exclure la liste |
---|---|---|
asynchrone | PRODUCT_MEMTAG_HEAP_ASYNC_INCLUDE_PATHS MEMTAG_HEAP_ASYNC_INCLUDE_PATHS | PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS MEMTAG_HEAP_EXCLUDE_PATHS |
synchroniser | PRODUCT_MEMTAG_HEAP_SYNC_INCLUDE_PATHS MEMTAG_HEAP_SYNC_INCLUDE_PATHS |
ou
Mode MTE | Paramètre |
---|---|
MTE asynchrone | MEMTAG_HEAP_ASYNC_INCLUDE_PATHS |
MTE synchrone | MEMTAG_HEAP_SYNC_INCLUDE_PATHS |
ou en spécifiant le chemin d'exclusion d'un exécutable :
Mode MTE | Paramètre |
---|---|
MTE asynchrone | PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS MEMTAG_HEAP_EXCLUDE_PATHS |
MTE synchrone |
Exemple (utilisation similaire à PRODUCT_CFI_INCLUDE_PATHS
)
PRODUCT_MEMTAG_HEAP_SYNC_INCLUDE_PATHS=vendor/$(vendor) PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS=vendor/$(vendor)/projectA \ vendor/$(vendor)/projectB
Activation de MTE à l'aide des propriétés système
Les paramètres de construction ci-dessus peuvent être remplacés au moment de l'exécution en définissant la propriété système suivante :
arm64.memtag.process.<basename> = (off|sync|async)
Où basename
représente le nom de base de l'exécutable.
Par exemple, pour définir /system/bin/ping
ou /data/local/tmp/ping
pour utiliser MTE asynchrone, utilisez adb shell setprop arm64.memtag.process.ping async
.
Activation de MTE à l'aide d'une variable d'environnement
Une autre façon de remplacer le paramètre de construction consiste à définir la variable d'environnement : MEMTAG_OPTIONS=(off|sync|async)
Si la variable d'environnement et la propriété système sont définies, la variable est prioritaire.
Activation de MTE pour les applications
S'il n'est pas spécifié, MTE est désactivé par défaut, mais les applications qui souhaitent utiliser MTE peuvent le faire en définissant android:memtagMode
sous la balise <application>
ou <process>
dans AndroidManifest.xml
.
android:memtagMode=(off|default|sync|async)
Lorsqu'il est défini sur la balise <application>
, l'attribut affecte tous les processus utilisés par l'application et peut être remplacé pour des processus individuels en définissant la balise <process>
.
À des fins d'expérimentation, les modifications de compatibilité peuvent être utilisées pour définir la valeur par défaut de l'attribut memtagMode
pour une application qui ne spécifie aucune valeur dans le manifeste (ou spécifie default
).
Ceux-ci se trouvent sous System > Advanced > Developer options > App Compatibility Changes
dans le menu des paramètres globaux. La définition NATIVE_MEMTAG_ASYNC
ou NATIVE_MEMTAG_SYNC
active MTE pour une application particulière.
Alternativement, cela peut être défini à l'aide de la commande am
comme suit :
$ adb shell am compat enable NATIVE_MEMTAG_[A]SYNC my.app.name
Création d'une image système MTE
Nous vous recommandons fortement d'activer MTE sur tous les binaires natifs pendant le développement et la mise en place. Cela permet de détecter rapidement les bogues de sécurité de la mémoire et fournit une couverture utilisateur réaliste, si elle est activée dans les versions de test.
Nous recommandons fortement d'activer MTE en mode synchrone sur tous les binaires natifs pendant le développement
SANITIZE_TARGET=memtag_heap SANITIZE_TARGET_DIAG=memtag_heap m
Comme pour toute variable du système de build, SANITIZE_TARGET
peut être utilisée comme variable d'environnement ou comme paramètre make
(par exemple, dans un fichier product.mk
).
Veuillez noter que cela active MTE pour tous les processus natifs, mais pas pour les applications (qui sont dérivées de zygote64
) pour lesquelles MTE peut être activé en suivant les instructions ci-dessus .
Configuration du niveau MTE préféré spécifique au processeur
Sur certains processeurs, les performances de MTE en modes ASYMM ou même SYNC peuvent être similaires à celles d'ASYNC. Cela vaut la peine d'activer des contrôles plus stricts sur ces processeurs lorsqu'un mode de contrôle moins strict est demandé, afin de bénéficier des avantages de détection d'erreurs des contrôles plus stricts sans les inconvénients en termes de performances.
Par défaut, les processus configurés pour s'exécuter en mode ASYNC s'exécuteront en mode ASYNC sur tous les processeurs. Pour configurer le noyau afin qu'il exécute ces processus en mode SYNC sur des processeurs spécifiques, la valeur sync doit être écrite dans l'entrée sysfs
/sys/devices/system/cpu/cpu<N>/mte_tcf_preferred
au moment du démarrage. Cela peut être fait avec un script d'initialisation. Par exemple, pour configurer les processeurs 0 à 1 pour exécuter les processus en mode ASYNC en mode SYNC et les processeurs 2 à 3 pour qu'ils soient exécutés en mode ASYMM, les éléments suivants peuvent être ajoutés à la clause init d'un script d'initialisation du fournisseur :
write /sys/devices/system/cpu/cpu0/mte_tcf_preferred sync write /sys/devices/system/cpu/cpu1/mte_tcf_preferred sync write /sys/devices/system/cpu/cpu2/mte_tcf_preferred asymm write /sys/devices/system/cpu/cpu3/mte_tcf_preferred asymm
Les pierres tombales des processus en mode ASYNC exécutés en mode SYNC contiendront une trace de pile précise de l'emplacement de l'erreur de mémoire. Cependant, ils n’incluront pas de trace de pile d’allocation ou de désallocation. Ces traces de pile ne sont disponibles que si le processus est configuré pour s'exécuter en mode SYNC.
int mallopt(M_THREAD_DISABLE_MEM_INIT, level)
où level
est 0 ou 1.
Désactive l'initialisation de la mémoire dans malloc et évite de modifier les balises de mémoire, sauf si cela est nécessaire pour l'exactitude.
int mallopt(M_MEMTAG_TUNING, level)
où level
est :
-
M_MEMTAG_TUNING_BUFFER_OVERFLOW
-
M_MEMTAG_TUNING_UAF
Sélectionne la stratégie d’allocation de balises.
- Le paramètre par défaut est
M_MEMTAG_TUNING_BUFFER_OVERFLOW
. -
M_MEMTAG_TUNING_BUFFER_OVERFLOW
- permet la détection déterministe des bogues de débordement et de sous-dépassement de tampon linéaire en attribuant des valeurs de balise distinctes aux allocations adjacentes. Ce mode a une chance légèrement réduite de détecter les bogues d'utilisation après libération car seule la moitié des valeurs de balise possibles sont disponibles pour chaque emplacement mémoire. Veuillez garder à l'esprit que MTE ne peut pas détecter les débordements dans le même granule de balise (morceau aligné sur 16 octets) et peut manquer de petits débordements même dans ce mode. Un tel débordement ne peut pas être la cause d'une corruption de la mémoire, car la mémoire d'un granule n'est jamais utilisée pour plusieurs allocations. -
M_MEMTAG_TUNING_UAF
- active des balises randomisées indépendamment pour une probabilité uniforme d'environ 93 % de détection de bogues spatiaux (débordement de tampon) et temporels (utilisation après libération).
En plus des API décrites ci-dessus, les utilisateurs expérimentés voudront peut-être connaître les éléments suivants :
- La définition du registre matériel
PSTATE.TCO
peut supprimer temporairement la vérification des balises ( exemple ). Par exemple, lors de la copie d'une plage de mémoire avec un contenu de balise inconnu ou lors de la résolution d'un goulot d'étranglement en termes de performances dans une boucle chaude. - Lors de l'utilisation
M_HEAP_TAGGING_LEVEL_SYNC
, le gestionnaire de crash du système fournit des informations supplémentaires telles que les traces de pile d'allocation et de désallocation. Cette fonctionnalité nécessite l'accès aux bits de balise et est activée en passant l'indicateurSA_EXPOSE_TAGBITS
lors de la définition du gestionnaire de signal. Il est recommandé à tout programme qui définit son propre gestionnaire de signal et délègue les plantages inconnus au système de faire de même.
MTE dans le noyau
Pour activer KASAN accéléré par MTE pour le noyau, configurez le noyau avec CONFIG_KASAN=y
, CONFIG_KASAN_HW_TAGS=y
. Ces configurations sont activées par défaut sur les noyaux GKI, à partir d' Android 12-5.10
.
Cela peut être contrôlé au moment du démarrage à l'aide des arguments de ligne de commande suivants :
-
kasan=[on|off]
- activer ou désactiver KASAN (par défaut :on
) -
kasan.mode=[sync |async ]
- choisir entre le mode synchrone et asynchrone (par défaut :sync
) -
kasan.stacktrace=[on|off]
- s'il faut collecter les traces de pile (par défaut :on
)- La collecte de traces de pile nécessite également
stack_depot_disable=off
.
- La collecte de traces de pile nécessite également
-
kasan.fault=[report|panic]
- s'il faut uniquement imprimer le rapport, ou également paniquer le noyau (par défaut :report
). Quelle que soit cette option, la vérification des balises est désactivée après la première erreur signalée.
Utilisation recommandée
Nous vous recommandons fortement d'utiliser le mode SYNC pendant la mise en place, le développement et les tests. Cette option doit être activée globalement pour tous les processus utilisant la variable d'environnement ou avec le système de build . Dans ce mode, les bogues sont détectés tôt dans le processus de développement, la base de code est stabilisée plus rapidement et le coût de détection des bogues plus tard dans la production est évité.
Nous recommandons fortement d'utiliser le mode ASYNC en production. Cela fournit un outil à faible surcharge pour détecter la présence de bogues de sécurité de la mémoire dans un processus ainsi qu'une défense plus approfondie. Une fois qu'un bug est détecté, le développeur peut exploiter les API d'exécution pour passer en mode SYNC et obtenir une trace précise de la pile à partir d'un ensemble échantillonné d'utilisateurs.
Nous vous recommandons fortement de configurer le niveau MTE préféré spécifique au processeur pour le SoC. Le mode Asymm a généralement les mêmes caractéristiques de performances que ASYNC et lui est presque toujours préférable. Les petits cœurs dans l'ordre affichent souvent des performances similaires dans les trois modes et peuvent être configurés pour préférer SYNC.
Les développeurs doivent vérifier la présence de plantages en vérifiant /data/tombstones
, logcat
ou en surveillant le pipeline DropboxManager
du fournisseur pour détecter les bogues des utilisateurs finaux. Pour plus d'informations sur le débogage du code natif Android, consultez les informations ici .
Composants de plateforme compatibles MTE
Dans Android 12, un certain nombre de composants système critiques en matière de sécurité utilisent MTE ASYNC pour détecter les pannes des utilisateurs finaux et agir comme une couche supplémentaire de défense en profondeur. Ces composants sont :
- Démons et utilitaires réseau (à l'exception de
netd
) - Bluetooth, SecureElement, NFC HAL et applications système
- démon
statsd
-
system_server
-
zygote64
(pour permettre aux applications de choisir d'utiliser MTE)
Ces cibles ont été sélectionnées sur la base des critères suivants :
- Un processus privilégié (défini comme un processus qui a accès à quelque chose que le domaine SELinux unprivileged_app n'a pas)
- Traite les entrées non fiables ( règle de deux )
- Ralentissement des performances acceptable (le ralentissement ne crée pas de latence visible par l'utilisateur)
Nous encourageons les fournisseurs à activer MTE en production pour davantage de composants, en suivant les critères mentionnés ci-dessus. Pendant le développement, nous vous recommandons de tester ces composants en utilisant le mode SYNC, pour détecter les bugs facilement corrigés et évaluer l'impact ASYNC sur leurs performances.
À l'avenir, Android prévoit d'élargir la liste des composants système sur lesquels MTE est activé, guidé par les caractéristiques de performances des conceptions matérielles à venir.