Das Projekt bpftime wurde vorgestellt, welches eine Laufzeitumgebung und eine virtuelle Maschine für die Ausführung von eBPF-Handlern im Benutzerspeicher entwickelt. bpftime ermöglicht die vollständige Ausführung von eBPF-Programmen zur Trace- und Prozessintervention im Benutzerspeicher unter Verwendung von Funktionen wie uprobe und der softwarebasierten Abfangung von Systemaufrufen. Es wird hervorgehoben, dass bpftime, durch die Eliminierung unnötiger Kontextwechsel, eine zehnfache Reduzierung der Overheadkosten im Vergleich zur Verwendung der uprobe- und uretprobe-Funktionalität des Linux-Kernels ermöglicht. Außerdem vereinfacht bpftime die Fehlersuche erheblich, kann potenziell auf Systemen ohne Linux-Kernel eingesetzt werden und benötigt keine erweiterten Berechtigungen, die für das Laden von eBPF-Anwendungen in den Kernel erforderlich sind. Der Code des Projekts ist in C/C++ geschrieben und wird unter der MIT-Lizenz vertrieben.
Das Abfangen von Systemaufrufen und die Integration von uprobe-Prüfungen erfolgt durch die Technik des Binärewritings, bei der die Aufrufe zu Systemaufrufen, Einstiegspunkten und lokalen Funktionen durch einen Sprung zu Debug-Handlern unter Verwendung einer Modifizierung des Maschinen-Codes der ausgeführten Anwendung ersetzt werden. Dies ist wesentlich effizienter als das Abfangen über uprobe auf der Linux-Kernel-Ebene.
Es werden Operationen zur Ersetzung oder Änderung von Funktionen, das Anbringen von Hooks und Filtern, das Umleiten, Blockieren oder Ersetzen von Parametern der Systemaufrufe, das Abfangen von Ein- und Ausstiegspunkten aus Funktionen sowie die Substitution eines Handlers an einer beliebigen Offset-Stelle im Code unterstützt. Bpftime kann an jeden laufenden Prozess im System ohne Notwendigkeit eines Neustarts oder einer Neubauten angehängt werden. Die Substitution von bpftime in Prozessen kann für laufende Prozesse über ptrace und für ladbare Prozesse über LD_PRELOAD erfolgen.
Im Rahmen von bpftime wird eine Runtime entwickelt, die es ermöglicht, eBPF-Programme an Systemaufruf-Tracepunkten und uprobe anzuhängen; virtuelle Maschine eBPF mit JIT für die isolierte Ausführung von eBPF-Programmen auf Benutzerebene (zudem wird AOT-Kompilierung unterstützt); ein Hintergrundprozess für die Interaktion mit dem Kernel und die Organisation der Kompatibilität mit dem Uprobe-Subsystem des Kernels (bpftime unterstützt den eBPF-Ladevorgang in den Benutzerspeicher aus dem Kernel, um die Zusammenarbeit mit eBPF-Programmen im Kernel zu ermöglichen, die beispielsweise für die Bearbeitung von Kprobes oder das Setzen von Netzwerkfiltern verwendet werden).
Die eBPF-Virtual Machine ist in Form einer dynamisch ladbaren Bibliothek gestaltet und bietet eine API, die der von ubpf ähnelt, wodurch sie für die Integration eBPF-Funktionen in andere Projekte genutzt werden kann. Zur aggregierten Datenerfassung aus mehreren Prozessen wird die Erstellung gemeinsamer eBPF Maps unterstützt, die im gemeinsamen Speicher platziert sind. Zusammen mit bpftime können typische eBPF-Handler verwendet werden, die für den Einsatz im Kernel geschrieben wurden, und für den Build können Standardtools auf Basis von clang und libbpf verwendet werden.
In der Benutzerumgebung können Systemverfolgungen wie BCC, bpftrace und Deepflow durchgeführt werden. Zum Beispiel wurde die Anwendung des sslsniff-Skripts aus dem BCC-Framework zur Analyse und Speicherung des verschlüsselten Traffics in nginx demonstriert. In den durchgeführten Tests reduzierte sich die Leistung von nginx bei der Ausführung von sslsniff im Kernelbereich um 58 %, während die Verlagerung des Handlers in den Benutzerraum zu einem Rückgang von 12,3 % führte.
Architektur der Prozessverfolgung unter Verwendung des ursprünglichen eBPF im Kernel:

Architektur der Verfolgung im Benutzerraum unter Verwendung von bpftime:

Hybridmodus, in dem bpftime gemeinsam mit eBPF im Kernel arbeitet, beispielsweise zur Einrichtung von Netzwerkfiltern oder zur Verlagerung einzelner Handler in den Benutzerraum:

In den zukünftigen Plänen sind folgende Punkte vorgesehen: die Möglichkeit zur Fehlerinjektion (Fault Injection); Hot Patching für die Änderung der Logik oder die Behebung von Fehlern in Binary-Builds; die Erstellung eines Moduls für Nginx, das Erweiterungen mittels eBPF-Programmen ermöglicht (zum Beispiel für die dynamische Routenwahl, Caching, Anwendung von Sicherheitsrichtlinien und Lastverteilung); die Erweiterung der Funktionen des FUSE-Subsystems (zum Beispiel die Erstellung von eBPF-Programmen zur Erweiterung des Dateisystems für Caching oder Zugriffssteuerung).
Quelle: opennet.ru
