1 points par GN⁺ 2024-03-20 | 1 commentaires | Partager sur WhatsApp
  • CVE-2023-6241 est un bug logique dans l’unité de gestion mémoire du GPU Arm Mali, qui permet à une application Android malveillante d’obtenir l’exécution arbitraire de code noyau et les privilèges root, même sur un Pixel 8 avec le MTE du noyau activé
  • Les appareils affectés sont les récents appareils à GPU Arm Mali utilisant le Command Stream Frontend (CSF), dont les Google Pixel 7 et Pixel 8
  • La vulnérabilité exploite une courte fenêtre où un verrou est relâché pendant l’extension de mémoire JIT afin de créer une incohérence entre les mappings GPU et le tableau des pages de backing
  • L’exploit utilise un mapping GPU résiduel vers des pages de backing libérées, force leur réutilisation comme PGD du contexte GPU, puis mappe la mémoire noyau et le code noyau
  • Le MTE détecte les incohérences entre pointeurs et tags mémoire, mais ce flux d’attaque se déroule hors du périmètre de protection du MTE, car le GPU accède directement aux adresses physiques

Portée de la vulnérabilité et état du correctif

  • CVE-2023-6241 est une vulnérabilité du GPU Arm Mali qui permet à une application Android malveillante d’obtenir l’exécution arbitraire de code noyau et les privilèges root sur l’appareil
  • Elle a été signalée à Arm le 15 novembre 2023 et corrigée dans le driver Arm Mali r47p0, publié le 14 décembre 2023
  • Le correctif Android a été inclus dans la mise à jour de sécurité de mars 2024
  • Les appareils touchés sont les récents appareils à GPU Arm Mali utilisant la fonction CSF (Command Stream Frontend), notamment les Google Pixel 7 et Pixel 8
  • Le fonctionnement de l’exploit a été confirmé sur un Pixel 8 avec le MTE du noyau activé

Modèle de défense de MTE sur Arm64

  • MTE (Memory Tagging Extension) est une fonctionnalité matérielle des processeurs Arm récents qui compare les tags des pointeurs et des blocs mémoire afin de détecter les corruptions mémoire
  • Les pointeurs Arm64 font 64 bits, mais l’espace d’adressage applicatif réel est généralement de 52 bits ou moins, ce qui permet d’utiliser une partie des bits de poids fort pour stocker les tags
  • Lors d’un overflow linéaire, le tag d’un bloc mémoire adjacent peut différer de celui du pointeur, et dans un use-after-free, des changements de tag pendant la libération et la réallocation peuvent provoquer une incohérence
  • Contrairement à des mesures d’atténuation de stade plus avancé comme kCFI, MTE est une mesure d’atténuation précoce conçue pour intercepter la corruption mémoire au moment où elle se produit
  • Le nombre de bits de tag étant limité, les collisions sont inévitables, mais même avec seulement 4 bits de tag, la probabilité de succès aléatoire tombe à 1/16
  • Des attaques par canal auxiliaire comme Spectre peuvent divulguer les valeurs des pointeurs et des blocs mémoire, permettant de deviner le bon tag et de contourner MTE, mais ce type de fuite est surtout accessible à un attaquant local
  • À l’heure actuelle, seul le Google Pixel 8 autorise l’activation de MTE dans les options développeur, et MTE est désactivé par défaut
  • L’activation de MTE dans le noyau nécessite des étapes supplémentaires

La race condition dans la mémoire JIT de Mali

  • Une application utilisateur qui utilise le driver GPU Mali ouvre le fichier du driver et crée puis initialise un objet noyau kbase_context via des appels ioctl
  • kbase_context gère plusieurs types de mémoire partagés entre l’appareil GPU et l’application en espace utilisateur
  • Les régions mémoire du GPU Mali sont représentées par kbase_va_region ; nr_pages indique la taille virtuelle et gpu_alloc->nents le nombre réel de pages de backing
  • La mémoire JIT est une mémoire native dont le cycle de vie est géré par le driver noyau ; l’application peut l’allouer ou la libérer via des commandes GPU
  • Sur les GPU CSF, les commandes logicielles et matérielles sont placées dans des files distinctes
    • KBASE_IOCTL_KCPU_QUEUE_CREATE permet de créer une kbase_kcpu_command_queue
    • KBASE_IOCTL_KCPU_QUEUE_ENQUEUE permet de mettre des commandes en file
    • BASE_KCPU_COMMAND_TYPE_JIT_ALLOC et BASE_KCPU_COMMAND_TYPE_JIT_FREE servent aux allocations et libérations JIT
  • kbase_jit_allocate recherche une région réutilisable dans le pool de mémoire JIT libérée et, si la taille physique est insuffisante, augmente les pages de backing via kbase_jit_grow
  • kbase_jit_grow peut relâcher temporairement kctx->reg_lock et kctx->mem_partials_lock lors de l’appel à kbase_mem_pool_grow
  • kctx->reg_lock protège l’accès concurrent aux régions mémoire ; le moment où ce verrou est relâché devient donc la fenêtre de race

Flux de déclenchement de CVE-2023-6241

  • Si le GPU accède à l’adresse d’une région mémoire qui n’est pas soutenue par des pages physiques de backing, un fault d’accès mémoire GPU se produit
  • kbase_mmu_page_fault_worker vérifie alors si la région peut être étendue et peut allouer puis mapper immédiatement les pages de backing nécessaires
  • Lors de leur création, les régions JIT satisfont la condition GROWABLE_FLAGS_REQUIRED, qui inclut KBASE_REG_PF_GROW et KBASE_REG_GPU_WR
  • Le flag KBASE_REG_DONT_NEED, ajouté lors de la libération d’une région JIT, est supprimé au début de kbase_jit_grow par kbase_mem_evictable_unmake
  • En conséquence, si un fault de page GPU est déclenché sur la même région JIT pendant la fenêtre de race de kbase_mem_pool_grow, le gestionnaire de fault peut étendre cette région
  • Si le gestionnaire de fault modifie reg->gpu_alloc->nents, les valeurs old_size et delta précédemment sauvegardées par kbase_jit_grow ne correspondent plus à l’état réel
  • Ensuite, kbase_alloc_phy_pages_helper_locked et kbase_mem_grow_gpu_mapping effectuent les allocations de pages de backing et les mappings GPU à partir de valeurs obsolètes, créant une incohérence entre les mappings GPU et le tableau pages
  • Cette race est facile à gagner, car kbase_mem_pool_grow inclut de grosses allocations mémoire

Changement de méthode d’attaque après le correctif de GHSL-2023-005

  • Dans la précédente vulnérabilité GHSL-2023-005, un autre thread pouvait réduire une région JIT avec KBASE_IOCTL_MEM_COMMIT, ce qui invalidait old_size et delta
  • Après le correctif de GHSL-2023-005, il n’est plus possible de modifier la taille de la mémoire JIT via l’ioctl KBASE_IOCTL_MEM_COMMIT
  • Dans CVE-2023-6241, il n’est donc plus possible de réduire la région dans la fenêtre de race, mais seulement de l’agrandir
  • En cas de simple agrandissement, seules quelques pages de backing finales ne sont pas mappées au GPU ; le mapping continu depuis le début de la région reste intact, ce qui ne pose pas immédiatement problème
  • L’exploit crée alors un nouveau mapping après le gap non mappé via un fault GPU supplémentaire, puis exploite une libération JIT pour faire coïncider le point de shrink avec l’intérieur de ce gap et obtenir un état exploitable

Hypothèse fragile lors du démontage des mappings GPU

  • kbase_mmu_teardown_pgd_pages parcourt les tables de pages GPU et marque les entrées comme invalides afin de supprimer les mappings d’adresses GPU
  • Cette fonction part du principe que si une PTE de niveau supérieur est invalide, toute la grande plage d’adresses couverte par cette entrée est déjà unmapped et peut être ignorée
  • Une seule PTE de niveau 2 couvre une plage de 512 pages
  • Dans un kbase_va_region normal, les adresses virtuelles mappées sont toujours continues depuis le début de la région, sans gap intermédiaire, ce qui rend ce comportement sûr
  • L’exploit de CVE-2023-6241 crée au contraire un gap non mappé entre des mappings, puis place le point de départ du shrink à l’intérieur de ce gap
  • kbase_mmu_teardown_pgd_pages rencontre une PTE invalide de niveau 2 et saute 512 pages, alors qu’une partie des adresses situées après peut en réalité être encore mappée
  • Les adresses GPU sautées à tort conservent l’accès aux pages physiques même après la libération des pages de backing

Comment cela mène à l’exécution de code noyau

  • Lorsqu’une région JIT est libérée, les pages de backing sont rendues, mais les mappings GPU laissés par erreur peuvent continuer à accéder à ces pages libérées
  • Ces pages de backing libérées peuvent ensuite être réutilisées comme d’autres pages noyau
  • L’une des techniques utilisées consiste à faire réutiliser une page de backing libérée comme PGD (page table global directory) du kbase_context GPU
  • L’allocation des pages de backing dans le driver Mali suit une hiérarchie
    • le driver prend d’abord des pages dans le kbase_mem_pool du kbase_context courant
    • si cela ne suffit pas, il utilise pool->next_pool
    • si cela ne suffit toujours pas, il alloue directement des pages via le buddy allocator du noyau
  • pool->next_pool est un pool mémoire géré par le driver Mali et partagé par tous les kbase_context ; il est aussi utilisé pour allouer les PGD des contextes GPU
  • Si une page libérée est réutilisée comme PGD, l’adresse GPU résiduelle permet au GPU de réécrire ce PGD
  • En réécrivant le PGD, il devient possible de mapper en GPU de la mémoire noyau arbitraire et du code noyau
  • À partir de là, on peut réécrire du code noyau pour obtenir l’exécution arbitraire de code noyau, et lire ou écrire des données noyau pour modifier les credentials d’un processus et désactiver SELinux
  • L’exploit pour Pixel 8 et les notes de configuration sont publiés dans le dépôt GitHub Security Lab

Pourquoi le contournement de MTE est possible

  • Ce flux d’exploit n’a pas besoin d’une étape dédiée au contournement de MTE
  • MTE sert à vérifier si le tag du bloc mémoire visé correspond au tag du pointeur afin de détecter les déréférencements invalides
  • Au moment du déclenchement de CVE-2023-6241, une incohérence apparaît entre le tableau pages et les mappings GPU, mais pris séparément, aucun des deux ne contient d’entrée invalide
  • Lorsque kbase_mmu_teardown_pgd_pages saute à tort la suppression d’un mapping GPU, l’adresse physique d’une page mémoire libérée reste présente dans la table de pages GPU
  • Quand le GPU accède à cette page libérée, il accède directement à son adresse physique sans passer par une vérification de déréférencement de pointeur
  • L’effet exact de MTE sur les accès mémoire du GPU n’est d’ailleurs pas clairement établi
  • En pratique, ce bug contourne donc la protection MTE en exploitant le chemin par lequel le GPU, en tant que coprocesseur, accède directement à la mémoire physique

Surface d’attaque restante après MTE

  • CVE-2023-6241 montre que même avec le MTE du noyau activé sur un Pixel 8, un seul bug peut suffire à atteindre l’exécution arbitraire de code noyau
  • MTE constitue une avancée importante dans l’atténuation des corruptions mémoire et peut rendre de nombreuses vulnérabilités de ce type inexploitées, mais ce n’est pas une défense universelle
  • Dans ce cas, le GPU contourne MTE en accédant directement à la mémoire physique
  • À mesure que les atténuations matérielles et logicielles côté CPU se multiplient, les coprocesseurs et leurs drivers noyau peuvent continuer à représenter une surface d’attaque puissante

1 commentaires

 
GN⁺ 2024-03-20
Avis sur Hacker News
  • Le point essentiel ici, c’est que les GPU sont depuis longtemps un casse-tête sur Android
    Les GPU disposent de droits d’accès très puissants à l’AP, ce qui leur permet en pratique de contourner les mesures d’atténuation placées en amont. Un bug dans le code de mapping du pilote peut déboucher sur une primitive d’attaque puissante, et cela a été exploité à plusieurs reprises dans des exploits observés dans la nature. Au final, il semble difficile que la situation change vraiment tant que l’architecture n’est pas repensée

    • À mon avis, les GPU mobiles à moitié conçus devraient cesser d’intégrer leur propre MMU et utiliser une IOMMU standard
    • Ici, AP veut dire quoi ?
  • Ce qui est intéressant dans cette vulnérabilité, c’est qu’il s’agit d’un bug logique dans l’unité de gestion mémoire du GPU Arm Mali, et qu’il permet de contourner Memory Tagging Extension
    Mais le reste de l’article semble expliquer que la cause réelle est une condition de concurrence, et que l’use-after-free n’en est que la conséquence

  • Les installations de GrapheneOS antérieures à la mise à jour de mars étaient-elles aussi affectées ?

    • L’un des principaux objectifs de GrapheneOS est de déployer les mises à jour de sécurité aussi vite que possible, donc si le correctif a été intégré en amont, il est presque certain qu’il a aussi été inclus dans GrapheneOS
      Il arrive parfois que GrapheneOS adopte le niveau de correctifs de sécurité AOSP avant sa publication, ou rétroporte des correctifs de sécurité d’AOSP ou du noyau qui ne sont pas encore publics
    • J’avais pensé que cela resterait probablement un problème même après la mise à jour de mars, car cela semblait lié à un problème proche du matériel dans le GPU, voire peut-être du firmware
      Cette mise à jour concernait la pile Bluetooth, après tout Édit : vous pouvez ignorer ça. Je l’avais confondu avec un billet récent du blog GrapheneOS intitulé « MTE a permis de trouver un problème qui affecte aussi toutes les applications système ». GrapheneOS a intégré le « niveau complet de correctifs de sécurité 2024-03-05 » dans la version 2024030600, donc ce correctif semble également inclus
  • La sûreté mémoire probabiliste d’Arm MTE constitue un tremplin vers le matériel CHERI déterministe, https://saaramar.github.io/memory_safety_blogpost_2022/ et https://news.ycombinator.com/item?id=39668053
    La bonne stratégie d’atténuation doit viser les primitives d’attaque de premier ordre, c’est-à-dire la cause racine du bug. Parmi les solutions matérielles, on trouve CHERI (Morello, CheriIoT) et MTE ; côté atténuations logicielles, il y a kalloc_type+dataPAC, AUTOSLAB, Firebloom, GuardedMemcpy, CastGuard, la réduction de la surface d’attaque ; et parmi les langages de programmation sûrs, Rust et Swift. MTE et CHERI se complètent bien et aident à éliminer ce type de bugs à la racine. MSR, MSRC et Azure Silicon ont poussé à miniaturiser CHERI jusqu’à la spécification du plus petit cœur RISC-V, le RISC-V32E
    Microsoft Research a publié en open source une pile matérielle/logicielle CHERI pour les appareils IoT, https://msrc.microsoft.com/blog/2023/02/first-steps-in-cheri...
    Les microcontrôleurs basés sur CHERI visent à obtenir de très fortes garanties de sécurité en co-concevant l’architecture du jeu d’instructions (ISA), l’interface binaire d’application (ABI), le modèle d’isolation et le cœur de la pile logicielle. Ces microcontrôleurs réalisent une atténuation déterministe de la sûreté spatiale via les capacités CHERI-ISA, une atténuation déterministe de la sûreté temporelle du tas et des piles inter-compartiments via des barrières de chargement, la mise à zéro, la récupération et un contrôle de flux d’information sur 1 bit, ainsi qu’une compartimentation fine grâce à des fonctionnalités CHERI-ISA supplémentaires et un petit moniteur
    David Chisnall, Université de Cambridge, https://lobste.rs/s/gnjx2n/c_can_be_memory_safe#c_9ohzku via https://eclypsium.com/blog/a-faster-path-to-memory-safety-ch...
    « Il y a environ 13 milliards de lignes de code C/C++ open source dans diverses bases informatiques de confiance, et davantage encore si l’on inclut le code propriétaire. Même si tout le monde arrêtait dès maintenant d’écrire du C/C++ et que tous les ingénieurs logiciels se concentraient sur la réécriture du code existant dans des langages sûrs, il faudrait quand même 5 à 10 ans pour tout remplacer, et il est très probable que cela introduirait aussi beaucoup de bugs logiques, car on remplacerait du code éprouvé de longue date par du nouveau code nécessitant d’autres algorithmes et structures de données pour correspondre aux idiomes autorisés des langages sûrs. »
    « Si l’on se contente d’arrêter d’écrire du code C/C++ sans faire de réécriture, alors, au rythme habituel de remplacement du code, il faudra environ 50 ans pour que la base informatique de confiance devienne entièrement sûre. Si tout le monde ne se met pas d’accord pour abandonner le C/C++, ce sera au minimum 100 ans. »
    « En revanche, si les principaux fabricants de CPU lancent des CPU CHERI dans les 5 prochaines années, alors, sans même que les programmeurs aient à changer de comportement, la plupart des machines — en particulier celles à forte valeur — disposeront de la sûreté mémoire d’ici 15 ans à partir d’aujourd’hui. »

    • Si CHERI vous intéresse pour des usages similaires à l’embarqué/IoT, lowRISC développe plusieurs plateformes d’évaluation FPGA pour CHERIoT : https://www.sunburst-project.org/
      La première est le système Sonata : https://github.com/lowRISC/sonata-system. Il se compose d’un PCB dédié avec FPGA, plusieurs périphériques et des connecteurs. La conception du PCB est terminée et il devrait être disponible via Mouser ; comme même le layout de la carte est open source, il sera aussi possible de l’assembler soi-même. En ce moment, ils travaillent sur le RTL pour le FPGA. Une fois terminé, cela donnera un système de type microcontrôleur basé sur CHERIoT, avec documentation et outils
      Ils développent aussi en plus le système Symphony, qui combine Sonata avec la racine de confiance OpenTitan Earl Grey : https://github.com/lowRISC/symphony-system
    • Il y a aussi Solaris SPARC ADI. C’est regrettable que cela soit largement oublié aujourd’hui, vu l’état actuel d’Oracle et de Solaris SPARC
    • C’est un bug matériel hors CPU, donc je ne vois pas bien comment CHERI pourrait aider
      En plus, la dernière fois que j’ai regardé, CHERI n’était pas sound. On pouvait encore écrire des bugs mémoire par-dessus ; est-ce que cela a été corrigé depuis ?
    • « 5 à 10 ans pour tout remplacer » me paraît beaucoup trop optimiste si on parle bien d’années
      Rien que les débats de type bike-shedding pourraient prendre autant de temps
    • Le problème fondamental semble être que l’utilisateur exécute du code malveillant et exploite une certaine collision de hachage MMU
      Cet exploit semble pouvoir être écrit dans la plupart des langages, y compris Rust
  • Le matériel est à ce point mauvais ? Mon dieu...

    • Le matériel GPU est truffé de bugs. On ne refabrique le matériel que lorsqu’il y a un problème qu’on ne peut pas contourner dans le pilote à un coût acceptable
      Cette approche est possible parce que les GPU n’autorisent pas un accès matériel relativement direct comme les CPU
    • C’est un bug de pilote exécuté sur le CPU
  • Excellente recherche et excellent billet ; c’est un peu surprenant, mais aussi agréable, de le voir publié sur le blog GitHub.
    Quelqu’un sait quelle est la « raison business » de GitHub pour mener ce type de recherche ? Je ne dis pas qu’il faut absolument une raison business, mais le voir là m’étonne un peu.

    • Man Yue Mo travaillait chez Semmle avant son acquisition par GitHub (https://blog.sonatype.com/steps-to-responsible-disclosure, https://github.blog/2019-09-18-github-welcomes-semmle/)
      Cette capacité de recherche a ensuite donné naissance au GitHub Security Lab. Semmle a créé CodeQL, désormais proposé par GitHub (https://docs.github.com/en/code-security/code-scanning/intro...). GitHub et Microsoft veulent associer CodeQL à des « analyses de sécurité approfondies » (https://www.microsoft.com/en-us/security/blog/2023/11/02/ann...)
      Ils continuent donc de financer ce type de recherche en sécurité novatrice, et les professionnels de la sécurité du secteur leur en sont reconnaissants.
    • Ce travail vient du Security Lab de GitHub : https://securitylab.github.com/
    • Le rachat par Microsoft a apporté les ressources nécessaires pour soutenir ce type de recherche.
      Il existe aussi des applis GitHub, et leur sécurité ne sort pas du périmètre de GitHub. Si un attaquant peut installer sur un téléphone une appli cachée, il peut faire toutes sortes de choses en se faisant passer pour l’utilisateur. Si la victime est une personne influente dans l’écosystème GitHub, l’impact peut être important ; trouver ce genre de vulnérabilités est donc aussi dans l’intérêt de GitHub.
    • GitHub propose aussi des Actions runners hébergés sur Arm.
      Ils peuvent donc avoir intérêt à examiner et valider les fonctions de sécurité du matériel Arm pour le sandboxing à l’aide de MTE.
    • J’y vois en pratique quelque chose de très proche de la recherche fondamentale [0].
      À première vue, un produit comme GitHub n’a pas forcément besoin d’experts en sécurité Android. Mais à long terme, il peut y avoir des bénéfices potentiels.
      [0]: https://en.wikipedia.org/wiki/Basic_research
  • Il est surprenant qu’on n’ait encore jamais vu de CPU et de téléphones avec très peu, voire pas du tout, de GPU, vendus comme des business phones.
    Les avantages en matière de sécurité, de coût et de consommation électrique semblent évidents.

    • L’inconvénient évident, c’est l’absence d’écran tactile haute résolution, ce qui reviendrait à retourner aux Blackberry ou aux Palm Treo. En pratique, ce type d’appareils a bien été vendu comme business phone.