Aller au contenu
Administration Linux medium

eBPF, c'est quoi ? Programmes, hooks et vérificateur expliqués

10 min de lecture

eBPF permet d'exécuter vos propres programmes à l'intérieur du noyau Linux, déclenchés par des événements, sans recompiler le noyau ni charger de module. C'est une machine virtuelle intégrée au noyau : vous lui donnez un petit programme, elle vérifie qu'il est sûr, puis l'exécute chaque fois que l'événement choisi se produit. Cette page explique le modèle mental complet, sans code : ce qu'est un programme eBPF, où il s'accroche, comment il communique avec l'espace utilisateur, et pourquoi le vérificateur est la pièce qui rend tout cela acceptable.

  • Définir eBPF sans le réduire au réseau
  • Situer où un programme eBPF s'exécute et ce qui le déclenche
  • Comprendre le rôle du vérificateur, des maps et de la compilation JIT
  • Distinguer eBPF d'un module noyau et d'un agent classique
  • Reconnaître les grands usages : observabilité, réseau, sécurité

eBPF signifie extended Berkeley Packet Filter. Le BPF d'origine, né en 1992, était un mini-langage pour filtrer les paquets réseau : c'est lui qui, derrière tcpdump, décide quels paquets capturer sans remonter chacun jusqu'à l'espace utilisateur. L'idée était déjà là : exécuter un petit programme dans le noyau, au plus près de l'événement.

Vers 2014, ce mécanisme a été généralisé. Le langage est devenu plus riche, la machine virtuelle plus complète, et surtout les points de déclenchement se sont ouverts bien au-delà du réseau : appels système, fonctions du noyau, événements de performance. C'est cette version étendue, l'eBPF, qui a tout changé. Le préfixe « e » est aujourd'hui souvent abandonné : on dit « BPF » pour désigner la technologie moderne.

Pour comprendre pourquoi eBPF a pris une telle place, il faut voir le dilemme qu'il tranche. Avant lui, observer ou modifier finement le comportement du noyau imposait un choix entre deux mauvaises options.

Écrire un module noyau donne tous les pouvoirs, mais un bug fait planter la machine entière (kernel panic), et un module mal écrit est une porte d'entrée pour un attaquant. C'est puissant et dangereux.

Passer par un agent en espace utilisateur est sûr, mais lent et partiellement aveugle : chaque information doit franchir la frontière entre le noyau et l'espace utilisateur, ce qui coûte cher, et beaucoup d'événements ne sont tout simplement pas visibles de l'extérieur.

eBPF offre une troisième voie : la puissance du noyau avec la sûreté d'un bac à sable. Le programme s'exécute dans le noyau, au contact de l'événement, mais il est prouvé inoffensif avant d'être chargé. C'est cette combinaison qui n'existait pas avant.

ApprochePuissanceSûretéCoût
Module noyautotaleun bug fait planter le systèmerecompilation, risque élevé
Agent espace utilisateurlimitée, vue partiellebonnefranchissements coûteux
eBPFproche du noyauvérifiée avant chargementfaible, exécution in-kernel

Le cycle de vie d'un programme eBPF tient en quatre temps. Les comprendre, c'est comprendre eBPF.

Le programme est généralement écrit dans un C restreint, puis compilé non pas en code machine classique, mais en bytecode eBPF : un jeu d'instructions propre à la machine virtuelle du noyau. Ce bytecode est le format que le noyau sait vérifier et exécuter.

Vous n'écrirez pas toujours ce C vous-même. Des outils comme bpftrace vous laissent décrire ce que vous voulez tracer dans un langage bien plus simple, et se chargent de produire le bytecode. Mais dessous, c'est toujours un programme eBPF.

C'est la pièce maîtresse, et ce qui distingue eBPF de tout ce qui l'a précédé. Avant de charger le programme, le noyau le confie à un vérificateur (verifier). Ce composant analyse tous les chemins d'exécution possibles et refuse le programme s'il ne peut pas prouver qu'il est sûr.

Le vérificateur garantit notamment que le programme se termine toujours (pas de boucle infinie qui figerait le noyau), qu'il n'accède qu'à une mémoire autorisée (pas de lecture ni d'écriture sauvage), et qu'il ne fuit pas d'informations sensibles du noyau. Un programme qui ne passe pas cette preuve n'est jamais chargé.

3. Le noyau l'attache à un hook et le compile en code natif

Section intitulée « 3. Le noyau l'attache à un hook et le compile en code natif »

Une fois vérifié, le programme est attaché à un point de déclenchement, un hook. Le hook, c'est l'endroit et le moment où votre code va s'exécuter. Les grandes familles :

  • kprobe : n'importe quelle fonction interne du noyau, à son entrée ou à sa sortie.
  • tracepoint : un point d'observation stable, prévu par les développeurs du noyau (par exemple « un processus vient de démarrer »).
  • uprobe : une fonction d'un programme en espace utilisateur, pas seulement du noyau.
  • XDP et tc : le tout début du traitement d'un paquet réseau, avant même qu'il ne remonte la pile. C'est là que Cilium agit.
  • LSM : les points de décision de sécurité du noyau, où l'on peut autoriser ou refuser une action.

Pour la performance, le noyau traduit ensuite le bytecode en code machine natif grâce à un compilateur JIT (Just-In-Time). Le programme tourne alors à la vitesse du noyau, pas à celle d'un interprète.

4. Il communique avec l'espace utilisateur via des maps

Section intitulée « 4. Il communique avec l'espace utilisateur via des maps »

Un programme eBPF ne vit pas isolé : il doit transmettre ce qu'il observe à un programme en espace utilisateur qui l'affichera ou l'exploitera. Ce pont, ce sont les maps : des structures de données (tables de hachage, tableaux, files) partagées entre le programme noyau et l'espace utilisateur.

Le programme eBPF écrit dans la map (par exemple, il incrémente un compteur d'appels système par processus), et l'outil en espace utilisateur lit la map pour vous présenter le résultat. Les maps sont aussi le moyen de configurer un programme depuis l'extérieur pendant qu'il tourne. Un guide entier de ce hub leur est consacré.

Le même mécanisme, greffer du code sûr sur un événement noyau, se décline en trois grands usages qui structurent ce hub.

Observer. Compter les appels système d'un processus, mesurer la latence d'une fonction, tracer les fichiers ouverts, profiler l'usage CPU en continu, le tout sans modifier l'application ni installer d'agent dans le conteneur. C'est le domaine de bpftrace, Parca, Pyroscope et Inspektor Gadget.

Router et filtrer le réseau. Traiter les paquets au plus tôt, décider du routage par identité plutôt que par adresse IP, appliquer des politiques réseau jusqu'au niveau applicatif. C'est ce que fait Cilium en remplaçant iptables par eBPF dans Kubernetes.

Sécuriser à l'exécution. Détecter en temps réel qu'un processus ouvre un shell suspect, lit un fichier sensible ou établit une connexion anormale, et, avec des outils comme Tetragon, bloquer l'action directement dans le noyau avant qu'elle n'aboutisse. C'est le terrain de Falco, Tetragon et Tracee.

  • eBPF exécute vos programmes dans le noyau Linux, déclenchés par des événements, sans module ni recompilation.
  • Ce n'est pas qu'un outil réseau : appels système, fonctions, paquets, décisions de sécurité, presque tout est un point d'accroche possible.
  • Le vérificateur prouve qu'un programme est sûr avant de le charger : pas de boucle infinie, pas d'accès mémoire interdit. C'est ce qui rend la technologie acceptable.
  • Un programme est attaché à un hook (kprobe, tracepoint, XDP, LSM…), puis compilé en code natif par le JIT pour la performance.
  • Les maps relient le programme noyau à l'espace utilisateur : elles transportent les données observées et la configuration.
  • eBPF sert à observer, router le réseau et sécuriser à l'exécution, mais reste un privilège sensible dont il faut maîtriser la surface d'attaque.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn