ABI jądra Linuxa — trzy kontrakty, jedna nazwa
Jeden z częściej mylonych tematów w świecie Linuxa i DevOps.
Ten artykuł wyjaśnia, czym jest ABI jądra, dlaczego istnieją trzy różne rzeczy pod tą samą nazwą i jakie ma to praktyczne konsekwencje dla administratora oraz dewelopera.
Zanim zaczniesz — API vs ABI
Zanim przejdziemy do jądra, warto rozróżnić dwa pojęcia, które często są mylone.
API (Application Programming Interface) to umowa na poziomie kodu źródłowego — mówi programiście:
„Wywołaj funkcję
open()z takimi argumentami, a dostaniesz deskryptor pliku."
ABI (Application Binary Interface) to umowa na poziomie skompilowanego kodu binarnego — mówi procesorowi:
„Pod numerem syscalla
2znajdziesz operacjęopen(). Argumenty przekaż w rejestrachrdi,rsi,rdx."
Krótko: API to umowa między programistami. ABI to umowa między skompilowanymi programami.
Analogia — gniazdko elektryczne
Wyobraź sobie gniazdko elektryczne. Producent urządzenia wie, że w Polsce jest 230V, wtyczka ma dwa okrągłe bolce w określonym rozstawie. To jest ABI.
Nie obchodzi go, co jest w środku ściany — może to być stara instalacja aluminiowa albo nowa miedziana. Dopóki gniazdko ma ten sam kształt i napięcie, urządzenie działa.
┌─────────────────────────────────────────┐
│ ŚCIANA (jądro) │
│ [stara instalacja] lub [nowa miedziana]│
│ ↕ ABI │
│ ⌀ gniazdko 230V │
└─────────────────────────────────────────┘
↕
[twoje urządzenie]
(program użytkownika)
Jądro Linuxa jest tą ścianą. Programy użytkownika — urządzeniami. Syscall read() zawsze będzie pod tym samym numerem, zawsze przyjmie te same argumenty. Nawet jeśli wewnętrzna implementacja jądra zmieni się nie do poznania.
Trzy różne ABI — ta sama nazwa
W kontekście jądra Linuxa słowo „ABI" może oznaczać trzy różne rzeczy. Mylenie ich to jedno z częstszych źródeł nieporozumień w dyskusjach o Linuxie.
┌──────────────────────────────────────────────────────────────┐
│ JĄDRO LINUXA │
│ │
│ ABI #1 ABI #2 ABI #3 │
│ Userspace kABI Dystrybucyjne │
│ ↕ ↕ ↕ │
│ Programy Moduły jądra Pakiety (.deb/.rpm) │
│ użytkownika (.ko) linux-image-X-Y-Z │
└──────────────────────────────────────────────────────────────┘
ABI #1 — Userspace ABI
Czym jest
To najważniejszy i najbardziej rygorystyczny kontrakt w całym projekcie Linuxa. Dotyczy komunikacji między jądrem a programami działającymi w przestrzeni użytkownika — wszystkim, co uruchamiasz jako zwykły proces.
Obejmuje:
- Syscalls — wywołania systemowe (
read,write,fork,mmap,open…) /proc— wirtualny system plików z informacjami o procesach i jądrze/sys— interfejs do sterowników i podsystemów jądra- Format sygnałów i struktury danych przekazywanych między procesem a jądrem
Zasada — „we don't break userspace"
Słynna zasada Linusa Torvaldsa oznacza ochronę zwykłych użytkowników, którzy po prostu chcą, żeby ich oprogramowanie działało. Nie jest to tylko deklaracja — to reguła, która skutkuje revertowaniem patchy naruszających tę zasadę, nawet jeśli są technicznie „poprawne".
Dokumentacja jądra definiuje cztery poziomy stabilności ABI:
| Poziom | Katalog | Gwarancja |
|---|---|---|
| stable | Documentation/ABI/stable/ |
Wsteczna kompatybilność ≥ 2 lata. Syscalls — nigdy nie łamane. |
| testing | Documentation/ABI/testing/ |
Stabilne, ale może się zmienić przed przejściem do stable. |
| obsolete | Documentation/ABI/obsolete/ |
Oznaczone do usunięcia, z terminem. |
| removed | Documentation/ABI/removed/ |
Usunięte — zachowane jako dokumentacja historyczna. |
Co NIE jest stabilnym ABI
Nie wszystko w /proc i /sys jest stabilne. Wyjątki:
/sys/kernel/debug— interfejsy debugowania są gwarantowanie niestabilne- Parametry
Kconfig— struktura zmienia się wraz z reorganizacją podsystemów - Interfejs walidatora BPF
- Metadane systemów plików
- Parametry linii komend jądra (
bootargs)
Ciekawostka — statyczny linking i syscalls
Linux różni się tu od Windows i macOS. Program linkowany statycznie, wywołujący syscalle bezpośrednio przez asembler (bez libc), będzie działał na arbitralnie nowszych wersjach jądra. To celowa, silna gwarancja — wynikająca z faktu, że twórcy jądra nie kontrolują, jaką wersję libc ma użytkownik po drugiej stronie interfejsu.
// To zadziała na jądrze 4.x, 5.x, 6.x i 7.x — bez rekompilacji
// o ile wywołujesz syscall bezpośrednio
mov rax, 1 ; syscall: write
mov rdi, 1 ; fd: stdout
mov rsi, msg ; buf
mov rdx, len ; count
syscall
ABI #2 — kABI (Kernel Module ABI)
Czym jest
To kontrakt między jądrem a modułami jądra — sterownikami, filesystemami i innymi komponentami ładowanymi przez insmod / modprobe jako pliki .ko.
Moduł jądra działa wewnątrz przestrzeni jądra, nie w przestrzeni użytkownika. Musi być binarnie zgodny z konkretną wersją jądra — musi wiedzieć, gdzie w pamięci są eksportowane funkcje jądra, jak wyglądają struktury danych itd.
Brak gwarancji upstream
W odróżnieniu od Userspace ABI — upstream Linux nie gwarantuje stabilności kABI. Każde wydanie jądra może zmienić wewnętrzne struktury, sygnatury funkcji, rozmieszczenie pól w structach.
Stąd znany problem: aktualizujesz jądro z 6.6 na 6.12 — moduł nvidia.ko, zfs.ko lub vboxdrv.ko przestaje działać i wymaga rekompilacji lub aktualizacji.
# Typowy błąd po aktualizacji jądra
$ modprobe nvidia
modprobe: ERROR: could not insert 'nvidia': Exec format error
# Moduł skompilowany pod inne kABI
Jak dystrybucje zarządzają kABI
Duże dystrybucje (RHEL, SUSE, Ubuntu LTS) zamrażają kABI na czas cyklu życia wydania. RHEL gwarantuje, że moduł skompilowany dla RHEL 9.0 będzie działał na RHEL 9.x przez cały cykl — bez rekompilacji.
Osiągają to przez tzw. whitelist symboli — zestaw eksportowanych funkcji jądra, których sygnatury zobowiązują się nie zmieniać, nawet jeśli backportują patche z upstream.
ABI #3 — Dystrybucyjne ABI (numer w nazwie pakietu)
Czym jest
To mechanizm zarządzania pakietami jądra w dystrybucjach opartych na Debianie i Ubuntu. Widoczny gołym okiem w nazwie pakietu:
linux-image-6.1.0-21-amd64
↑↑
└┴── to jest numer ABI dystrybucji
Jak działa
Podczas każdego buildu jądra generowany jest plik Modules.symver zawierający listę eksportowanych funkcji. Każda funkcja otrzymuje hash opisujący jej sygnaturę — argumenty i wartość zwracaną.
# Fragment Modules.symver
0x1a2b3c4d kmalloc vmlinux EXPORT_SYMBOL
0x5e6f7a8b schedule vmlinux EXPORT_SYMBOL_GPL
Nowy build jest porównywany z poprzednim. Jeśli jakikolwiek hash się zmienił — ABI zostało złamane, numer ABI zostaje zinkrementowany, co zmienia nazwę pakietu.
# Przed zmianą ABI
linux-image-6.1.0-21-amd64
# Po zmianie ABI (np. łatka bezpieczeństwa zmieniła sygnaturę funkcji)
linux-image-6.1.0-22-amd64
Praktyczna konsekwencja
Ponieważ zmiana numeru ABI zmienia nazwę pakietu, apt nie zaktualizuje automatycznie systemu do nowego jądra. To mechanizm ochronny — bez niego pakiety modułów zewnętrznych (DKMS, sterowniki zamknięte) załadowałyby niekompatybilne .ko do nowego jądra.
# apt widzi dwa oddzielne pakiety, nie aktualizację
linux-image-6.1.0-21-amd64 → linux-image-6.1.0-22-amd64
# Moduły zewnętrzne muszą być przebudowane dla nowego ABI
Pakiety obsługujące DKMS (Dynamic Kernel Module Support) przebudowują się automatycznie po zmianie ABI — właśnie po to, by ten problem rozwiązać.
Podsumowanie — tabela porównawcza
| Userspace ABI | kABI | Dystrybucyjne ABI | |
|---|---|---|---|
| Kto po obu stronach | Jądro ↔ programy użytkownika | Jądro ↔ moduły .ko |
Pakiet jądra ↔ pakiety modułów |
| Stabilność | Bardzo wysoka — syscalls nigdy nie łamane | Brak gwarancji upstream | Zarządzana numerem w nazwie pakietu |
| Gdzie widoczne | /proc, /sys, strace |
modprobe, dmesg |
uname -r, apt, dpkg -l |
| Kogo dotyczy | Każdego użytkownika | Deweloperów modułów, vendorów sterowników | Administratorów, systemów pakietowych |
| Przykład złamania | Zmiana numeru syscalla read |
Zmiana struktury sk_buff w networking |
Aktualizacja jądra bez inkrementacji ABI |
Gdzie szukać więcej
- Linux Kernel Docs — ABI description — oficjalna dokumentacja poziomów stabilności
- kernel.org — Documentation/ABI/README — polityka ABI w źródłach jądra
- Opensource.com — A 10-minute guide to the Linux ABI
- LWN.net — Specifying the kernel ABI
- SUSE SolidDriver — Kernel ABI Stability
- Debian Wiki — DebianKernelABIChanges
- Ubuntu Wiki — KernelTeam/BuildSystem/ABI
- offlinemark.com — Syscall ABI: Linux vs Windows/macOS
// brak komentarzy