- Explique la structure mémoire des processus sous Linux au niveau du fonctionnement réel, avec une présentation étape par étape de la relation entre espace d’adressage virtuel et mémoire physique
- Décrit concrètement comment un processus possède et accède à la mémoire, en se concentrant sur des mécanismes clés comme les tables de pages, VMA, mmap, page fault, CoW
- Présente comment observer l’état mémoire de chaque processus via le système de fichiers
/proc, ainsi que le rôle d’outils de diagnostic avancés comme pagemap et kpageflags
- Traite de l’optimisation des performances et des techniques de dirty tracking en espace utilisateur grâce à des fonctionnalités récentes du noyau comme Transparent Huge Pages (THP), userfaultfd et PAGEMAP_SCAN
- Explique aussi des principes de conception du noyau liés à la sécurité et aux performances, comme PTI contre Meltdown, flush du TLB et politique W^X, afin d’offrir une compréhension d’ensemble de la gestion mémoire sous Linux
Structure de base de la mémoire d’un processus
- Lorsqu’un programme s’exécute, tout se passe comme s’il disposait d’une immense mémoire continue, mais en réalité le noyau Linux l’organise dynamiquement page par page
- Le CPU consulte les tables de pages pour traduire les adresses virtuelles en cadres physiques
- S’il n’existe pas de mapping, un défaut de page (page fault) se produit, et le noyau alloue une nouvelle page ou renvoie une erreur
- Si la RAM physique manque, le noyau déplace sur disque les pages inutilisées ou supprime des pages de fichiers pour libérer de l’espace
/proc est un système de fichiers virtuel construit par le noyau en mémoire, qui expose sous forme de fichiers l’état des processus et du noyau
Espace d’adressage et VMA
- Chaque processus possède un objet d’espace d’adressage, dont l’intérieur est composé de plusieurs VMA (Virtual Memory Area)
- Une VMA est une plage d’adresses continue avec les mêmes droits (R/W/X) et le même backend (mémoire anonyme ou fichier)
- La table de pages est la structure référencée par le matériel, qui stocke les informations de mapping (PTE) entre pages virtuelles et pages physiques
- Les modifications de l’espace d’adressage s’effectuent via trois appels système
mmap : crée une nouvelle zone
mprotect : modifie les droits
munmap : supprime le mapping
- La page est l’unité de base de 4 KiB, et certains systèmes prennent aussi en charge de grandes pages de 2 MiB et 1 GiB
Voir la disposition mémoire avec /proc/self/maps
- La commande
cat /proc/self/maps permet d’inspecter la carte mémoire du processus
- On y voit le code, les données et la bss de l’exécutable, le heap, les mappings anonymes, les bibliothèques partagées, la pile, etc.
- Les zones
[vdso] et [vvar] contiennent du code et des données mappés par le noyau pour des appels système rapides
Principe de fonctionnement de mmap
mmap n’alloue pas immédiatement de la mémoire réelle, il enregistre une promesse dans l’espace d’adressage
- Les pages sont allouées au premier accès
- Pour un mapping de fichier,
offset doit être aligné sur la taille de page, et un accès au-delà de la fin du fichier provoque SIGBUS
MAP_SHARED répercute directement les modifications dans le fichier, tandis que MAP_PRIVATE crée des pages indépendantes par Copy-on-Write (CoW)
MAP_FIXED_NOREPLACE améliore la sûreté en échouant si l’adresse demandée est déjà mappée
Premier accès et défaut de page
- Lors du premier accès à un nouveau mapping, si le CPU ne trouve pas l’entrée correspondante dans la table de pages, un page fault se produit
- Le noyau vérifie la validité de l’adresse, les droits d’accès et l’existence de la zone
- Pour un mapping anonyme, il alloue une nouvelle page remplie de zéros ; pour un mapping de fichier, il lit depuis le page cache
- Un minor fault se produit lorsque les données sont déjà en RAM, un major fault lorsqu’une E/S disque est nécessaire
- La pile est protégée par une guard page ; un accès trop en dessous provoque
SIGSEGV
fork() et le Copy-on-Write de MAP_PRIVATE
- Lors d’un
fork, le parent et l’enfant partagent les mêmes pages physiques, marquées en lecture seule pour les deux
- Une nouvelle page n’est copiée qu’au moment de l’écriture afin de conserver leur indépendance
- Les mappings de fichiers
MAP_PRIVATE fonctionnent selon le même principe
- Options associées
vfork : partage l’espace d’adressage du parent
clone(CLONE_VM) : crée un thread
MADV_DONTFORK, MADV_WIPEONFORK : excluent le mapping du processus enfant ou le réinitialisent à zéro
Changement de droits et invalidation du TLB
- Lorsqu’on modifie les droits d’une page avec
mprotect, le noyau scinde éventuellement la VMA et modifie la table de pages, puis effectue une invalidation du TLB
- Selon la politique W^X, une page ne peut pas être à la fois inscriptible et exécutable
- Le TLB (Translation Lookaside Buffer) est un cache des traductions d’adresses récentes ; son invalidation introduit un léger délai
Observation détaillée via /proc
/proc/<pid>/maps, smaps et smaps_rollup permettent de voir, par zone, les droits, la RSS et l’usage des HugePages
/proc/<pid>/pagemap fournit l’état page par page (présence, swap, PFN, etc.), mais les PFN ne sont pas accessibles aux utilisateurs ordinaires
/proc/kpagecount et /proc/kpageflags affichent, pour chaque PFN, le nombre de mappings et les propriétés de page (anonyme, fichier, dirty, etc.)
mincore et SEEK_DATA/SEEK_HOLE permettent d’identifier les zones de données et les trous dans les fichiers creux
- En combinant
PAGEMAP_SCAN et userfaultfd, il est possible d’implémenter un dirty tracking en espace utilisateur
Transparent Huge Pages (THP) et mTHP
- THP regroupe automatiquement la mémoire fréquemment accédée en grandes pages (2 MiB, par exemple) afin d’améliorer l’efficacité du TLB
- Le thread
khugepaged fusionne les pages adjacentes
- mTHP prend en charge des grandes pages variables (folio) de tailles diverses, comme 16 KiB ou 64 KiB
- On peut vérifier leur utilisation via
AnonHugePages et FilePmdMapped dans /proc/self/smaps
- La configuration globale du système se gère dans
/sys/kernel/mm/transparent_hugepage/
MADV_HUGEPAGE et MADV_NOHUGEPAGE permettent un contrôle par zone
Dirty tracking en espace utilisateur
userfaultfd et PAGEMAP_SCAN permettent de ne copier que les pages modifiées
- Le noyau effectue en une seule opération atomique le scan et la protection en écriture
- Cette approche est efficace pour les snapshots, la live migration, etc.
Mécanisme de flush du TLB
- Sur x86, l’invalidation du TLB se fait de deux façons
INVLPG : invalide une seule page
- rechargement de la racine des tables de pages pour un flush complet
PCID et INVPCID réduisent les flush inutiles grâce à une gestion des tags TLB par processus
tlb_single_page_flush_ceiling est le seuil utilisé par le noyau pour choisir entre flush page par page et flush complet
Réponse à Meltdown : Page Table Isolation (PTI)
- Meltdown est une vulnérabilité où des données du noyau peuvent être exposées via le cache pendant l’exécution spéculative
- Linux utilise PTI (Page Table Isolation) pour séparer les espaces d’adressage utilisateur et noyau
- À l’entrée, un basculement de
CR3 active une table de pages dédiée au noyau
PCID est utilisé pour minimiser les flush du TLB
- Cette protection est activée par défaut et peut être désactivée avec
nopti
Procédure sûre du noyau pour modifier les mappings
- Lors d’une modification de mapping, l’ordre est le suivant
- traitement des règles de cache
- modification de la table de pages
- invalidation du TLB
- Les mappings internes au noyau (
vmap, vmalloc) synchronisent eux aussi cache et TLB avant et après les E/S
- Certaines architectures nécessitent un flush du cache d’instructions après copie de code
Structure de pile et d’appel sur x86
- En mode 64 bits, les registres RIP, RSP et RBP sont utilisés, et la pile croît vers le bas
- Selon l’ABI System V AMD64, les arguments sont passés dans RDI, RSI, RDX, RCX, R8, R9, et la valeur de retour dans RAX
- Le mode utilisateur fonctionne en ring 3, le noyau en ring 0, et les appels système ainsi que les interruptions passent par des gates
Situations d’erreur et diagnostic
mmap → EINVAL : erreur d’alignement de l’offset du fichier
mmap → ENOMEM : manque d’espace virtuel ou limitation d’overcommit
- accès à un mapping de fichier →
SIGBUS : accès au-delà de l’EOF
mprotect(PROT_EXEC) → EACCES : montage noexec ou politique W^X
- augmentation de la RSS après
fork() : copie de pages due au CoW
- écrasement d’un mapping existant avec
MAP_FIXED → MAP_FIXED_NOREPLACE recommandé
Checklist pratique
- Obtenir immédiatement de la mémoire :
mmap + PROT_READ|PROT_WRITE + MAP_PRIVATE|MAP_ANONYMOUS
- Génération de code : conserver W^X, puis
mprotect(PROT_READ|PROT_EXEC)
- Mapping de fichier : aligner
offset sur la taille de page, ne pas accéder au-delà de l’EOF
- En cas de nombreux page faults :
MADV_WILLNEED ou pré-accès
- Analyse de l’usage mémoire :
/proc/<pid>/smaps_rollup → /proc/<pid>/maps
fork de gros processus : prendre en compte le CoW, utiliser exec dans l’enfant
- Environnement sensible à la latence : observer THP/mTHP,
mlock et le comportement du TLB
Aucun commentaire pour le moment.