Aller au contenu principal
own2pwn
gpu/gpu-security.tsx

Hacker un GPU : DMA, side-channel et fuites mémoire

Surface d'attaque des GPU : exploitation de la mémoire partagée (CVE-2016-2067), DMA via IOMMU, absence d'ASLR sur la heap GPU, fuites par registres non remis à zéro et impact sur le framebuffer.

Maxime Jérôme··5 min de lecture

Hello ! o/

Les GPU (Graphics Processing Unit) sont aujourd'hui embarqués dans des millions d'appareils. On sait que la sécurité du CPU est critique puisqu'il pilote intégralement la machine. Mais les GPU ont le droit de lire la même mémoire que le CPU -- et plusieurs vulnérabilités y ont été découvertes, bien plus qu'on ne le croit généralement.

Un autre problème vient de la documentation : elle est souvent indigente, comme chez Nvidia. Les vendeurs refusent d'exposer leurs architectures internes pour pouvoir les modifier sans invalider les systèmes tiers qui s'appuieraient dessus. Résultat : la recherche en sécurité GPU avance à tâtons.

CVE-2016-2067 : exploitation de la mémoire partagée

Commençons par un exemple concret sur un GPU intégré (iGPU). Dans ce cas, le GPU partage la RAM physique avec le CPU -- il n'y a pas de VRAM dédiée.

igpu-shared-memory.txt
  ┌───────────────────────────────────────────────┐
  │                  RAM physique                 │
  │                                               │
  │   ┌──────────────┐    ┌──────────────────┐   │
  │   │  CPU pages   │    │   GPU pages      │   │
  │   │  (kernel)    │    │  (driver Adreno) │   │
  │   └──────┬───────┘    └────────┬─────────┘   │
  │          │  read-only (CPU)    │ writable (GPU)│
  │          └────────────────────┘               │
  │             même région physique !             │
  └───────────────────────────────────────────────┘
GPU intégré : CPU et GPU partagent la même RAM physique. Les pages mappées en lecture seule côté CPU peuvent être accessibles en écriture côté GPU.

La faille exposée par cette CVE est simple mais dévastatrice : le driver graphique Adreno mappe des pages mémoire en read-only du côté CPU, mais en writable du côté GPU. Un attaquant avec accès au GPU peut donc écrire dans des zones que le CPU considère protégées en lecture seule.

Pour les GPU discrets (dGPU) avec leur propre VRAM, on pourrait penser que la situation est plus saine. L'IOMMU (Input-Output Memory Management Unit) -- l'équivalent du MMU du CPU mais pour les périphériques -- est optionnel et configuré par l'OS. Sa présence n'est pas garantie.

Attaque DMA : du GPU vers la RAM CPU

DMA signifie Direct Memory Access -- accès direct à la mémoire sans passer par le CPU. Voilà comment ça se passe pour un GPU discret :

  1. Le CPU mappe une région mémoire dans l'espace du kernel GPU.
  2. Une fois mappée, le GPU peut accéder directement à cette mémoire CPU via DMA.
  3. Si le code kernel GPU est trop volumineux pour tenir dans l'I-Buffer (instruction buffer), il est stocké en RAM GPU et peut être réécrit dynamiquement.
  4. Un process updater n'a plus qu'à localiser le code kernel en mémoire physique et en modifier le contenu.
dma-attack-gpu.txt
  dGPU                          CPU
  ┌─────────────────────┐       ┌──────────────────┐
  │  VRAM               │       │  RAM physique     │
  │  ┌───────────────┐  │ DMA   │  ┌─────────────┐ │
  │  │ kernel code   │◄─┼───────┼──│ mapped page │ │
  │  │ (I-Buffer     │  │       │  └─────────────┘ │
  │  │  overflow)    │  │       └──────────────────┘
  │  └───────┬───────┘  │
  │          │          │
  │  ┌───────▼───────┐  │
  │  │ updater proc  │  │
  │  │ localise +    │  │
  │  │ réécrit code  │  │
  │  └───────────────┘  │
  └─────────────────────┘
Attaque DMA : le process updater localise le code kernel en RAM GPU et le réécrit. Illustré par l'incident PixelVault.

Ce scénario s'est produit dans la pratique avec le driver PixelVault, qui tournait indéfiniment. L'updater process avait donc tout le temps pour localiser le driver en mémoire, modifier son code, et même spéculer son espace mémoire.

Source : Zhiting Zhu et al., "Understanding The Security of Discrete GPUs" (2016)

Registres non remis à zéro : fuite de clefs crypto

Après l'exécution d'un kernel GPU, rien ne garantit la RAZ (Remise A Zéro) des registres. Un kernel suivant peut donc lire les valeurs laissées par le précédent. C'est une attaque de type information disclosure qui peut aller très loin.

Attaque démontrée sur SSLShader
Des chercheurs ont exploité cette propriété contre SSLShader, un programme qui accélère le calcul SSL sur GPU. En lisant les registres non remis à zéro, ils ont récupéré la clef AES symétrique utilisée pour le chiffrement. Les architectures Fermi et Kepler de Nvidia étaient vulnérables.

La technique permet également des attaques par rétro-ingénierie : en lisant les valeurs résiduelles, on peut reconstituer des données confidentielles traitées par un kernel tiers.

Buffer overflow sur la heap GPU et absence d'ASLR

Les kernels GPU basés sur CUDA se programment en C++. Les mêmes vulnérabilités que sur CPU existent donc : buffer overflow sur le tas (heap), corruption de pointeurs, etc.

On peut par exemple récrire un pointeur vtable (table de fonctions virtuelles C++) pour détourner le flux d'exécution. Les attaques par COOP (Counterfeit Object-Oriented Programming) sont applicables.

Mais le vrai problème de fond, c'est l'absence totale d'ASLR (Address Space Layout Randomization) sur les GPU. Sur CPU, la résolution d'une adresse par un processus passe par la table des pages : l'adresse virtuelle est traduite en adresse physique unique, différente à chaque exécution. Ce mécanisme n'existe pas sur GPU.

gpu-no-aslr.txt
  CPU (avec ASLR)                GPU (sans ASLR ni mémoire virtuelle)
  ┌─────────────────────┐        ┌─────────────────────────────────┐
  │ Proc A: 0x7f3a...   │        │ Kernel A: cudaMalloc → 0x4000   │
  │   table des pages   │        │ Kernel B: cudaMalloc → 0x4000   │
  │   ──► addr physique │        │                                 │
  │       (unique)      │        │  meme adresse physique !        │
  │                     │        │  donnees non effacees de A      │
  │ Proc B: 0x7c1b...   │        │  lisibles par B                 │
  │   table des pages   │        └─────────────────────────────────┘
  │   ──► autre addr    │
  └─────────────────────┘
Sans mémoire virtuelle ni ASLR : deux kernels GPU pointent vers la même adresse physique. Les données du kernel A sont toujours accessibles par le kernel B.

Concrètement : deux processus GPU peuvent pointer vers la même adresse physique. Et à la fin d'un processus, les données ne sont pas effacées. Les appels à cudaMalloc retournent la même adresse d'un appel à l'autre. Si un kernel ne libère pas correctement la mémoire allouée, on peut avoir accès à l'intégralité de la heap.

gpu-heap-leak.txt
  Timeline d'exécution GPU
  ──────────────────────────────────────────────────►
  │
  │  [Kernel A]  cudaMalloc(0x4000, 1024)
  │              traitement (données sensibles en heap)
  │              fin -- heap NON libérée
  │
  │  [Kernel B]  cudaMalloc(0x4000, 1024)   ← même adresse !
  │              lecture heap → données de A encore présentes
  │              possible: clefs, tokens, buffers réseau...
  │
Sans protection mémoire hardware : si un kernel oublie de libérer sa heap, le suivant peut lire toutes les données residuelles.

Source : Michael Patterson, "Vulnerability analysis of GPU computing"

Le framebuffer : espionnage visuel

Dernier point, souvent négligé : le GPU gère le framebuffer, c'est-a-dire l'image courante affichée sur l'écran. Un malware avec accès GPU peut donc capturer en temps réel tout ce qui s'affiche sur le moniteur, sans passer par aucune API système normalement surveillée.

Synthese des vecteurs d'attaque GPU
  • Mémoire partagée iGPU : pages mappées writable côté GPU mais read-only côté CPU (CVE-2016-2067)
  • DMA sans IOMMU : accès direct à la RAM CPU depuis le GPU si l'IOMMU n'est pas activé ou contournable
  • Registres non RAZ : fuite de données inter-kernels (clefs AES, tokens, données sensibles)
  • Heap sans ASLR : adresses prévisibles, données non effacees entre kernels
  • Framebuffer : capture visuelle furtive via malware GPU

Merci pour votre lecture :)

La securite GPU est encore un chantier ouvert. La documentation sparse des vendeurs, l'absence de protections matérielles équivalentes au CPU, et la montée en puissance des workloads GPU (IA, cryptographie, rendu) en font une surface d'attaque de plus en plus critique.