Extension MTE (Memory Tagging Extension) Arm

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)

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)

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)

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'indicateur SA_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 .
  • 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.

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.