# cat blog/kernel-abi.txt

title = ABI Linux Kernel — czego nie wiesz, a powinieneś

date = 2026-05-31

ABI Linux Kernel — czego nie wiesz, a powinieneś

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 2 znajdziesz operację open(). Argumenty przekaż w rejestrach rdi, 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

← back

[ulther@blog ~]$ cat comments/kernel-abi.log

// brak komentarzy

[ulther@blog ~]$ comment --post kernel-abi