Przedstawiono projekt bpftime, który rozwija środowisko uruchomieniowe oraz maszynę wirtualną do wykonywania programów eBPF w przestrzeni użytkownika. Bpftime umożliwia całkowite uruchamianie programów eBPF do śledzenia i ingerencji w działanie procesów w przestrzeni użytkownika, wykorzystujących takie możliwości jak uprobe i programowe przechwytywanie wywołań systemowych. Zauważono, że dzięki wyeliminowaniu zbędnych przełączeń kontekstu, bpftime pozwala osiągnąć dziesięciokrotne zmniejszenie kosztów w porównaniu z wykorzystaniem funkcji uprobe i uretprobe, oferowanych przez jądro Linux. Ponadto, bpftime znacznie upraszcza debugowanie, potencjalnie może być stosowane w systemach bez jądra Linux i nie wymaga rozszerzonych uprawnień wymaganych do załadowania aplikacji eBPF do jądra. Kod projektu napisany jest w językach C/C++ i jest udostępniany na licencji MIT.
Przechwytywanie wywołań systemowych oraz integracja testów uprobe została zrealizowana przy użyciu techniki przepisania kodu wykonywalnego (binary rewriting), w której wywołania wywołań systemowych, punktów wejścia i lokalnych funkcji są zamieniane na przejścia do debugujących obsługujących poprzez modyfikację maszynowego kodu wykonywanej aplikacji, co jest znacznie bardziej efektywne niż organizowanie przechwytywania przy użyciu uprobe na poziomie jądra Linux.
Obsługiwane są operacje zamiany lub modyfikacji funkcji, przyczepiania uchwytów (hooków) i filtrów, przekierowywania, blokowania lub zamiany parametrów wywołań systemowych, przechwytywania punktów wejścia i wyjścia z funkcji, a także podstawianie uchwytu w dowolnym przesunięciu w kodzie. Bpftime może być podłączony do dowolnego działającego procesu w systemie bez potrzeby ich ponownego uruchamiania lub przebudowy. Podstawienie bpftime w procesach może być realizowane dla działających procesów poprzez ptrace, a dla ładowanych przez LD_PRELOAD.
W ramach bpftime rozwija się środowisko uruchomieniowe, które umożliwia przypinanie programów eBPF do punktów śledzenia wywołań systemowych oraz uprobe; maszyna wirtualna eBPF z JIT do izolowanego wykonywania programów eBPF na poziomie procesu użytkownika (dodatkowo wspierana jest kompilacja AOT); działający w tle proces do interakcji z jądrem i organizacji zgodności z subsystemem uprobe jądra (bpftime obsługuje tryb ładowania eBPF do przestrzeni użytkownika z jądra, aby umożliwić współpracę z eBPF-programami w jądrze, stosowanymi na przykład do przetwarzania kprobe lub wystawiania filtrów sieciowych).
Wirtualna maszyna eBPF jest realizowana w formie biblioteki dynamicznej i udostępnia API, podobne do ubpf, co pozwala na jej wykorzystanie do integracji funkcjonalności eBPF w innych projektach. Aby zsumować dane z kilku procesów, wspierane jest tworzenie współdzielonych eBPF Map, umieszczanych w pamięci dzielonej. Wraz z bpftime mogą być używane standardowe przetworniki eBPF, napisane do wykorzystania w jądrze, a do kompilacji mogą być stosowane standardowe narzędzia oparte na clang i libbpf.
Z bpftime w przestrzeni użytkownika mogą działać takie systemy śledzenia, jak BCC, bpftrace i Deepflow. Na przykład, zaprezentowano zastosowanie skryptu sslsniff z frameworka BCC do analizy i zapisywania zaszyfrowanego ruchu w nginx. W przeprowadzonych testach wydajność nginx podczas wykonywania sslsniff po stronie jądra spada o 58%, a przy przeniesieniu przetwornika do przestrzeni użytkownika o 12,3%.
Architektura śledzenia procesów z wykorzystaniem oryginalnego eBPF w jądrze:

Architektura śledzenia w przestrzeni użytkownika z wykorzystaniem bpftime:

Tryb hybrydowy, w którym bpftime współpracuje z eBPF w jądrze, na przykład do instalowania filtrów sieciowych lub przenoszenia poszczególnych przetworników do przestrzeni użytkownika:

Do planów na przyszłość należy: możliwość wprowadzania wyjątków (Fault Injection); gorące nakładanie poprawek (Hot Patching) w celu zmiany logiki działania lub naprawy błędów w binarnych wersjach; stworzenie modułu do Nginx, umożliwiającego tworzenie rozszerzeń za pomocą programów eBPF (na przykład do dynamicznego wyboru tras, cachowania, stosowania polityk bezpieczeństwa i równoważenia obciążenia); rozszerzenie możliwości subsystemu FUSE (na przykład utworzenie w formie eBPF-programów rozszerzeń do FS do cachowania lub zarządzania dostępem).
Źródło: opennet.ru
