https://www.cnblogs.com/revercc/p/17803876.html Połączenie między programem uprobe eBPF a kernel/events/uprobe.c polega zasadniczo na tym, że mechanizm eBPF ponownie wykorzystuje natywną infrastrukturę uprobe jądra do implementacji funkcji hook funkcji stanu użytkownika. Konkretnie, uprobe eBPF jest "aplikacją" frameworka kernel uprobe, który jest połączony przez wewnętrzny łańcuch wywołań jądra i strukturę danych. Połączenie rdzeniowe: eBPF polega na frameworku kernel uprobe do implementacji hooków Kernel uprobe.c jest główną implementacją natywnej sondy stanu użytkownika (uprobe) jądra Linux i odpowiada za: Zarządzanie rejestracją i anulowaniem sond stanów użytkownika (np. register_uprobe(), unregister_uprobe()). Obsługuje wstawianie punktów przerwania (zapisywanie instrukcji punktu przerwania do adresu funkcji docelowej, takich jak int3 w x86). Przechwycaj zdarzenia wyzwalające punkty przerwania (utknęły w przetwarzaniu stanu jądra, gdy program jest wykonywany do punktu przerwania). Wywołaj wcześniej zarejestrowaną funkcję callback (czyli logikę hook). Program eBPF uprobe (taki jak przykład hook libc.so opisany) zasadniczo rejestruje funkcję callback eBPF opartą na uprobe z jądrem za pomocą ładowarki eBPF (np. bcc, libbpf), która całkowicie opiera się na infrastrukturze udostępnionej przez uprobe.c. Specyficzny łańcuch połączeń: przepływ z programu eBPF do uprobe.c Gdy rejestrujesz uprobe przez ładowarkę eBPF (np. attach_uprobe bcc), podstawowy proces wygląda następująco: Loader eBPF inicjuje żądanie rejestracji Loader (np. kod Pythona bcc) informuje jądro za pomocą wywołania systemowego (np. bpf() lub perf_event_open()), że "chcę zawiesić hook eBPF na funkcji openat libc.so" i przekazuje kod bajtowy programu eBPF. Weryfikacja jądra i przygotowanie programów eBPF Weryfikator eBPF jądra sprawdza legalność programu, aby upewnić się, że nie narusza on bezpieczeństwa jądra. Po przekazaniu załaduj program eBPF do jądra i użyj "funkcji callback eBPF" (czyli logiki uprobe_openat, którą napisałeś). Ponowne użycie jądra interfejsu rejestracyjnego uprobe.c wywołuje funkcję register_uprobe() w uprobe.c, rejestruje "natywny uprobe" i używa funkcji wywołania eBPF jako "handlera wyzwalającego" tego uprobe. Kluczowe jest to: istotą uprobe eBPF jest powiązanie callbacka typu eBPF z natywnym uprobe'em jądra. uprobe.c wstawia punkt przerwania i czeka na jego wyzwolenie. Uprobe.c zapisuje instrukcję punktu przerwania (taką jak int3 w x86) do pamięci stanu użytkownika na podstawie zarejestrowanego adresu docelowego (adres Openat w libc.so) i zapisuje oryginalną instrukcję punktu przerwania (aby wznowić wykonanie po wyzwalaniu). Wywołania funkcji wywołują punkty przerwania, uprobe.c wywołuje wywołania eBPF Gdy aplikacja wywołuje libc.so:openat, wykonanie instrukcji punktu przerwania uruchamia pułapkę i przechodzi do stanu jądra. Na ten moment: Jądro wywołuje funkcję uprobe_handler() (logikę przetwarzania jądra) w uprobe.c. uprobe_handler() sprawdzi informacje rejestracyjne odpowiadające punktowi przerwania i stwierdzi, że jest powiązany z callbackiem eBPF, więc wywoła program eBPF (czyli uprobe_openat, który napisałeś). Po uruchomieniu programu eBPF (np. zbieranie parametrów, zapisywanie do ringbuf), uprobe_handler() przywraca oryginalną instrukcję i pozwala programowi kontynuować wykonywanie. Streszczenie: Relacje między nimi kernel/events/uprobe.c to infrastruktura podstawowa, która zapewnia podstawowe funkcje, takie jak wstawianie, przechwytywanie i odzyskiwanie punktów przerwania stanów użytkownika, oraz stanowi podstawę wszystkich sond stanu użytkownika (w tym eBPF uprobe, debugowanie gdb itp.). Program uprobe eBPF to aplikacja wyższej warstwy oparta na tej infrastrukturze, która rejestruje funkcje callback eBPF i pozwala jądru na wykonanie logiki eBPF po wyzwalaniu uprobe, co pozwala na efektywne śledzenie funkcji stanu użytkownika. Krótko mówiąc: uprobe dla eBPF to "użytkownik", a uprobe.c to "dostawca usług", a pierwszy polega na tym drugim, aby zakończyć rejestrację, wyzwalanie i wykonanie haków. |