3 points par GN⁺ 2025-11-05 | Aucun commentaire pour le moment. | Partager sur WhatsApp
  • 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
    1. traitement des règles de cache
    2. modification de la table de pages
    3. 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

  • mmapEINVAL : erreur d’alignement de l’offset du fichier
  • mmapENOMEM : 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_FIXEDMAP_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.

Aucun commentaire pour le moment.