Loading AI tools
De Wikipédia, l'encyclopédie libre
Le BPF (Berkeley Packet Filter) ou BSD packet filter, est un code minimaliste injecté dans le kernel, il permet à l'utilisateur d'effectuer du filtrage réseau dans le kernel. Au cours de ses différentes versions (Exemple: eBPF(extend Berkeley Packet Filter)), de nouveaux outils ont été mis en place afin de faciliter la production de programme BPF. De plus de nouveaux domaines d'utilisation sont devenus exploitables, tel que le monitoring d’événement dans le kernel et son traçage. Différents problèmes existent encore à ce jour, principalement au niveau du vérificateur.
Le BPF, initialement conçu en 1992, est un code binaire minimaliste injecté dans le kernel depuis l’espace utilisateur. Il permet à l’utilisateur de filtrer les paquets circulant dans le kernel tout en évitant de devoir les transférer vers l’espace utilisateur[1],[2],[3].
Toutefois, de par son côté minimaliste il possède peu d’instruction, de plus, sa difficulté de programmation fait qu’il est utilisé par un petit nombre d’applications telles que tcpdump[2],[3].
En 2013, Alexei Starovoitov (ingénieur logiciel spécialisé dans le kernel chez Facebook) refaçonne complètement BPF en y ajoutant de nouvelles fonctionnalités et en améliorant ses performances. Cette nouvelle version est appelée eBPF, opposé à cBPF (classic BPF) désignant la version antérieure. Ce nouveau langage permet de concevoir une plus grande variété de cas d’utilisation, qui se décompose en deux domaines d’applications. Le premier domaine est le traçage du kernel et la supervision, tandis que le deuxième est la programmation réseaux[1].
Il existe de multiples cas d'utilisation tel que du tracing, du filtrage pare-feu ou de la mise en réseau de conteneurs[2], du filtrage de socket, du filtrage de paquet et du contrôle de trafic[4]. Il est également possible de faire du filtrage au plus bas niveau de la pile réseau, c’est-à-dire directement par le pilote de la carte d’interface réseau. Ainsi des paquets peuvent être jetés très tôt; par exemple XDP(Express Data Path) est un projet utilisant les eBPF qui est utilisable pour la prévention d’attaque par déni de service[4]. De plus, les BPF permettent de faire de la surveillance efficace et flexible des performances d’un réseau pour des applications dans des machines virtuelles, un exemple est le framework vNetTracer[3].
Voici une liste non exhaustive de projet utilisant les BPFs[5] :
BPF utilise des graphes de flot de contrôle CFG afin de représenter les critères utilisés dans l'analyse de paquets, et aussi pour sa performance sur les expressions de modèle d’arbre[23],[24]. De plus ces graphes sont utilisés par BPF pour mettre en place des règles de filtrage permettant de réduire efficacement les chemins CFG inutiles à l'analyse d'un paquet ainsi que les comparaisons redondantes[24],[25].
Le transfert de donnée fait par les appels systèmes se fait de manière bidirectionnelle entre le noyau et l'espace utilisateur. Ceux-ci permettant le bon déroulement de l'injection du code binaire d’eBPF dans le noyau ainsi que la communication des données du noyau cible vers un processus de l'espace utilisateur[26].
Les paquets associés par le programme BPF sont en partie copiés dans un buffer avant d’être transférés dans l’espace utilisateur. BPF permet au programme de définir le nombre d’octets du paquet devant être copiés dans le buffer. Cela permet de faire des économies en temps en évitant de copier des données non nécessaires. Par exemple, pour les paquets TCP/IP/Ethernet, 134 octets suffisent. Un programme voulant faire des statistiques sur les trames TCP sera en mesure de copier seulement une partie des trames économisant ainsi du temps d’exécution[24].
eBPF est une extension de BPF qui en diffère de plusieurs manières : le chargement des programmes est réalisé par l'utilisateur, et une vérification est faite sur la terminaison d'un programme afin de s'assurer que celui-ci est sûr à exécuter[27]. La dernière extension apportée par eBPF est la possibilité d'accéder à des structures de données partagées[27].
En effet pour partager ces données, eBPF utilise trois mécanismes distincts:
Depuis la version 3.15 du noyau Linux les fonctions de la machine virtuelle de eBPF fournissent un accès à la couche liaison grâce à des instructions basiques et à l'introduction de nouvelles fonctionnalités d’eBPF, ceci permet de créer un moyen de filtrer et d’analyser les paquets du réseau[29]. Cependant les programmes eBPF peuvent être invoqués dans différentes couches de la pile réseaux ce qui permet de traiter les paquets capturés avant de progresser vers la couche suivante[25].
EBPF s’appuie sur un code binaire compilé en instructions natives du CPU au chargement de l'extension dans le noyau. Contrairement au bytecode classique comme Java par exemple, le compilateur et le temps d’exécution d’eBPF n’imposent pas de type ni de sécurité mémoire. Au lieu de cela, la sécurité est renforcée par un vérificateur statique qui vérifie que le programme ne peut pas accéder à des structures de données du noyau ou provoquer des erreurs de page[30].
Des risques de sécurité et de stabilité sont présents lorsqu'un code est exécuté dans le kernel. Pour pallier ces risques, BPF compte sur un interpréteur pour exécuter sûrement un programme. Tandis que pour réduire ces risques, eBPF introduit un vérificateur Linux qui s’assure que chaque programme respecte certaines conditions avant d’être chargé dans le kernel évitant ainsi un fort coût en temps en vérification. Il s’assure que le programme est en mesure de se terminer, qu'il ne contient pas de boucle pouvant engendrer un blocage du kernel ou que certaines instructions soient inaccessibles. Et dans un autre temps, il vérifie chaque instruction et la simule afin d’être sûr que l’état des registres et des piles soient valides, empêchant ainsi l'accès à la mémoire ou à l’état du kernel hors de sa zone allouée[30],[31].
L'implémentation d'eBPF fait en sorte d'être sûr et sécurisé pour le kernel mais aussi dans le but d'offrir la possibilité de mettre en place différentes exectutions dans le kernel tel que le traçage du kernel ou des fonctions réseau[32].
Les appels système permettent le chargement d'un code binaire. Pour que le chargement soit un succès, il faut que le programme soit vérifié par le vérificateur eBPF[32].
Les programmes eBPF peuvent être instanciés en même temps, même sur différents hooks. Ainsi ils peuvent opérer individuellement ou être chainés[32].
Un programme BPF peut être en écoute sur une interface, lorsque cela arrive le pilote de l’interface fait appel à ce programme en premier. BPF distribue alors les paquets à chaque filtre qui participe au traitement. Les filtres définis par l'utilisateur s’appliquent alors aux paquets et décident si le paquet est accepté ou non et combien de bytes de chaque paquet doivent être sauvegardés.Pour chaque filtre qui accepte le paquet, BPF copie la quantité de données demandé que le buffer à associé à ce filtre[23].
Lorsque des modifications de topologies surviennent ou un changement dans les applications, il devient nécessaire de modifier les règles servant de firewall afin de pouvoir ajouter, supprimer ou modifier les ports et les adresses impactés par les filtres. Pour cela, grâce à la stratégie de bitmap, qui permet de garder le programme C simple, il suffit de créer un nouveau programme avec de nouvelles maps et de charger la map avec de nouvelles clés-valeur et de l'échanger avec l’ancien programme, imitant ainsi le comportement de iptables-restore[33].
Les filtres sont interprétés sous forme de bytecode dans un kernel avec interpréteur. Dans le cas de l'absence de celui-ci, eBPF peut utiliser le compilateur à la volée du kernel (JIT compiler) afin de traduire les bytecodes produit par eBPF en code natif et de réaliser des optimisations optionnelles dépendant de la machine[34].
Clang (LLVM natif) permet à l’utilisateur de compiler son code C en instruction eBPF dans un fichier ELF[35].
La programmation en instruction eBPF peut être compliquée. C’est pour cela qu’un toolkit appelé BPF Compiler Collection (BCC) existe permettant à l’utilisateur de créer facilement des programmes eBPF. BCC englobe LLVM et l’améliore afin de fournir à l’utilisateur la possibilité de définir des eBPF maps dans un code C et de compiler ce code C en programme eBPF[28],[25],[29],[4].
La machine virtuelle de BPF+ possède 5 classes d’opération :
En 2019 différents problèmes se posent encore au développeur tel que:
Il existe des restrictions dans l’utilisation des services kernel, peu de fonctions d’aide et aucun espace utilisateur ou service tiers ne peut être utilisé dans les programmes eBPF[36].
Certaines contraintes rendent les vérifications des programmes flexibles et permettent l’intégrité du système, tel que l’impossibilité de faire des allocations dynamiques, d’accéder aux structures de données kernel, d’appeler les APIs kernel ou de faire des sauts d’instructions indirect. Ainsi que le fait qu’elle s'exécute sur un seul thread et donc ont un temps d'exécution lié aux nombres d’instructions[30],[32].
Les cBPF utilise une stratégie de mise en mémoire tampon qui rend sa performance totale jusqu’à 100 fois plus rapide que le NIT (Network Interface Tap (en)) de SUN s'exécutant sur le même matériel[23].
Le temps d'exécution d’un appel à BPF est d’environ 6 microseconde par paquet pour un filtre qui rejette tous les paquets[23].
Les eBPF sont jusqu'à 4 fois plus rapides sur les architecture x86_64 que l’implémentation des cBPF pour certain microbenchmark de filtrage réseaux, et la plupart sont 1.5 fois plus rapides[31].
Il existe un facteur 10 d’amélioration de performance des eBPF comparé aux IPTABLES et NFTABLES[4].
XDP, étant attaché au plus bas niveau de la pile réseau, est adéquat pour le filtrage grossier de paquet tel que la prévention d'attaques par déni de service. Il peut produire quatre fois les performances en comparaison à une tâche similaire dans le kernel[4].
De plus, XDP offre aussi des améliorations sur la latence médiane en utilisant le code compiler en JIT (Just In Time), jusqu'à 45% d’amélioration de performance avec comme coût une plus haute valeur de latence aberrantes[4].
XDP offre un compromis, il n’offre pas des performances aussi bonnes que les frameworks dédiés hautes performances qui outrepasse le kernel. Mais offre une intégration kernel, c’est-à-dire que les paquets peuvent passer par la pile réseau avec tous ses avantages. Bien qu’il traite seulement 50% du débit d’une ligne 10 GbE, cela représente les performances d’un seul cœur, c’est-à-dire qu’il évolue avec le nombre de cœur CPU[4].
BPF signifie à l’origine “Berkeley packet filter", développés pour UNIX en 1992 afin de faire du filtrage de paquets réseau[4],[37], ils permettent alors une amélioration de performances dans les applications de monitoring réseau tel que “tcpdump”[37],[38],[1],[2],[3].
À l’origine les BPF n’ont pas pour fonction de jeter des paquets reçus, mais décrits comme filtre ils peuvent associer des paquets, copier des paquets, et envoyer des paquets[24]. Initialement les BPF sont implémentés dans le kernel linux 2.x, disposant de 2 registres 32 bits[25],[39],[31],[38].
Puis en 2013, Alexei Starovoitov, propose une amélioration des BPF différenciant maintenant les cBPF (classic BPF) des eBPF (extended BPF). Un des changements les plus notables est le passage à 10 registres de 64 bits[25],[39],[31],[38], ainsi que l’appel de fonction dans le kernel grâce à une nouvelle instruction[31],[39],[38].
Une autre différence est l'absence de persistance d’état dans les cBPF[40] alors que dans eBPF les états peuvent être maintenus grâce au maps[5].
Les eBPF font leur apparition à la version 3.x du kernel linux[31],[25], avec des améliorations continues telles qu’un compilateur JIT (Just In Time)[4],[1], de nouvelles fonctionnalités telles que les “maps” et les “tail calls”[1].
Un documentaire sur YouTube retrace, avec les auteurs des premiers commits, la genèse de eBPF[41] entre 2013 et 2023.
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.