Le projet bpftime a été présenté, développant un runtime et une machine virtuelle pour exécuter des gestionnaires eBPF dans l'espace utilisateur. Bpftime permet d'exécuter entièrement des programmes eBPF de traçage et d'intervention sur les processus dans l'espace utilisateur, utilisant des fonctionnalités telles que uprobe et l'interception des appels système. Il est noté qu'en éliminant les commutations de contexte superflues, bpftime permet d'atteindre une réduction des frais généraux par un facteur de dix par rapport à l'utilisation de la fonctionnalité uprobe et uretprobe fournie par le noyau Linux. De plus, bpftime simplifie considérablement le débogage, peut potentiellement être appliqué sur des systèmes sans noyau Linux et ne nécessite pas de privilèges avancés nécessaires pour charger une application eBPF dans le noyau. Le code du projet est écrit en C/C++ et est distribué sous la licence MIT.
L'interception des appels système et l'intégration des vérifications uprobe sont réalisées en utilisant la technique de réécriture de code exécutable (binary rewriting), où les appels aux appels système, aux points d'entrée et aux fonctions locales sont remplacés par un saut vers des gestionnaires de débogage par la modification du code machine de l'application en cours d'exécution, ce qui est considérablement plus efficace que l'organisation de l'interception utilisant uprobe au niveau du noyau Linux.
Les opérations de remplacement ou de modification de fonctions, d'attachement de gestionnaires (hooks) et de filtres, de redirection, de blocage ou de remplacement des paramètres des appels système, ainsi que l'interception des points d'entrée et de sortie des fonctions, ainsi que le remplacement du gestionnaire à un décalage arbitraire dans le code sont pris en charge. Bpftime peut être attaché à tout processus en cours d'exécution dans le système sans nécessiter leur redémarrage ou recompilation. L'injection de bpftime dans les processus peut se faire pour les processus actifs via ptrace, et pour ceux à charger via LD_PRELOAD.
Dans le cadre de bpftime, un runtime est en développement, permettant d'attacher des programmes eBPF aux points de traçage des appels système et de uprobe; machine virtuelle eBPF avec JIT pour l'exécution isolée des programmes eBPF au niveau du processus utilisateur (support complémentaire de la compilation AOT) ; un processus en arrière-plan pour interagir avec le noyau et organiser la compatibilité avec le sous-système uprobe du noyau (bpftime prend en charge le mode de chargement eBPF dans l'espace utilisateur depuis le noyau pour collaborer avec les programmes eBPF dans le noyau, utilisés par exemple pour traiter les kprobes ou pour appliquer des filtres réseau).
La machine virtuelle eBPF est conçue sous forme de bibliothèque dynamique et fournit une API similaire à ubpf, permettant son intégration dans d'autres projets. Pour l'agrégation des données de plusieurs processus, la création de cartes eBPF communes, stockées en mémoire partagée, est prise en charge. Avec bpftime, il est possible d'utiliser des gestionnaires eBPF types, écrits pour une utilisation dans le noyau, et les outils standards basés sur clang et libbpf peuvent être utilisés pour la compilation.
Avec bpftime dans l'espace utilisateur, des systèmes de traçage tels que BCC, bpftrace et Deepflow peuvent être exécutés. Par exemple, l'utilisation du script sslsniff du framework BCC pour analyser et sauvegarder le trafic chiffré dans nginx a été démontrée. Les tests ont montré que la performance de nginx lors de l'exécution de sslsniff côté noyau diminue de 58 %, tandis que l'exécution du gestionnaire dans l'espace utilisateur réduit la performance de 12,3 %.
Architecture de traçage des processus utilisant l'eBPF d'origine dans le noyau :

Architecture de traçage dans l'espace utilisateur utilisant bpftime :

Mode hybride dans lequel bpftime fonctionne en conjonction avec l'eBPF dans le noyau, par exemple pour l'établissement de filtres réseau ou le déplacement de gestionnaires spécifiques dans l'espace utilisateur :

Parmi les projets futurs, il est noté : la possibilité d'injection d'exceptions (Fault Injection) ; le patching à chaud (Hot Patching) pour modifier la logique de fonctionnement ou corriger les erreurs dans les builds binaires ; la création d'un module pour Nginx, permettant de développer des extensions à l'aide de programmes eBPF (par exemple, pour un choix de routes dynamique, la mise en cache, l'application de politiques de sécurité et l'équilibrage de charge) ; l'extension des fonctionnalités du sous-système FUSE (par exemple, la création d'extensions au système de fichiers sous forme de programmes eBPF pour la mise en cache ou la gestion des accès).
Source : opennet.ru
