29 kwietnia ujawniono publicznie CVE-2026-31431, nazwaną “CopyFail”. Podatność siedziała w kernelu przez 9 lat — od 2017 roku. Pozwala każdemu lokalnemu użytkownikowi uzyskać roota. Bez race condition, bez zgadywania offsetów, ze 100% skutecznością. Cały exploit mieści się w 732-bajtowym skrypcie Pythona.

Co jest podatne

Moduł algif_aead w podsystemie kryptograficznym kernela (AF_ALG). Dotyczy praktycznie każdej dystrybucji z kernelem zbudowanym od 2017 roku:

  • Ubuntu 20.04 – 24.04
  • RHEL 10.1
  • Amazon Linux 2023
  • SUSE 16
  • Debian, Fedora, Arch, Rocky Linux, AlmaLinux

CVSS: 7.8 (HIGH) — lokalny dostęp, niskie uprawnienia, brak interakcji użytkownika.

Jak do tego doszło

Podatność powstała z połączenia trzech niezależnych zmian, z których każda osobno wyglądała sensownie:

2011 — dodano algorytm authencesn dla IPsec Extended Sequence Numbers. Używa bufora docelowego jako scratch space i zapisuje 4 bajty (seqno_lo) za obszarem tagu uwierzytelniającego.

2015 — AF_ALG dostał wsparcie AEAD z możliwością splice(). Operacje były out-of-place — oddzielne scatterlisty źródłowa i docelowa.

2017 — optymalizacja w algif_aead.c (commit 72548b093ee3) ustawiła req->src = req->dst (operacja in-place). Od tego momentu strony page cache trafiały do zapisywalnej scatterlisty docelowej.

Mechanizm exploita

Atak wykorzystuje fakt, że splice() przekazuje do kernela bezpośrednie referencje do stron page cache — nie kopie. Po optymalizacji z 2017 roku scatterlista wyjściowa łańcuchuje te strony przez sg_chain().

Algorytm authencesn zapisuje 4 bajty scratch data pod kontrolowanym offsetem. Te 4 bajty lądują bezpośrednio w page cache wybranego pliku.

Atakujący kontroluje:

  • Plik docelowy — dowolny plik, do którego ma prawo odczytu
  • Offset zapisu — przez parametry splice (offset, długość, assoclen)
  • Wartość zapisu — 4 bajty seqno_lo pochodzą z bajtów 4–7 AAD w sendmsg()

Krok po kroku:

  1. Otwórz socket AF_ALG, binduj do authencesn(hmac(sha256),cbc(aes))
  2. Dla każdego 4-bajtowego fragmentu shellcode’u — skonstruuj parę sendmsg() + splice() celującą w /usr/bin/su
  3. recv() uruchamia deszyfrowanie, authencesn zapisuje dane do stron page cache
  4. execve("/usr/bin/su") ładuje zmodyfikowany binarkę z page cache — shellcode wykonuje się jako root

Kernel nie oznacza uszkodzonej strony jako dirty, więc plik na dysku pozostaje niezmieniony. Narzędzia sprawdzające integralność plików na dysku niczego nie wykryją.

Co to oznacza w praktyce

  • Każdy nieuprzywilejowany użytkownik lokalny może zostać rootem
  • Działa przez granice kontenerów — page cache jest współdzielony
  • Omija kontrole integralności plików na dysku
  • 100% deterministyczny — brak race condition, brak prób
  • W momencie ujawnienia żadna dystrybucja nie miała jeszcze wydanego poprawionego pakietu kernela

Poprawka

Fix w kernelu (commit a664bf3d603d) przywraca operację out-of-place w algif_aead.c. req->src wskazuje na TX SGL (który może zawierać strony page cache ze splice), a req->dst na RX SGL (bufor użytkownika). Mechanizm sg_chain łączący strony page cache z zapisywalnym celem został wyeliminowany.

Jak się zabezpieczyć teraz

Zanim pojawi się poprawiony kernel w Twojej dystrybucji, zablokuj moduł algif_aead:

cat > /etc/modprobe.d/disable-algif.conf << 'EOF'
blacklist algif_aead
install algif_aead /bin/false
EOF

Jeśli moduł jest już załadowany:

lsmod | grep algif_aead

Jeśli jest — potrzebny restart lub rozładowanie modułu (jeśli nic go nie używa).

W środowiskach kontenerowych i Kubernetes warto dodatkowo zablokować tworzenie socketów AF_ALG przez seccomp. Priorytet mają nody z dostępem dla niezaufanych workloadów i CI/CD runnery.

Sprawdź czy jesteś podatny

Zespół Theori udostępnił skrypt testowy test_cve_2026_31431.py — zwraca kod 0 jeśli system jest poprawiony, 2 jeśli podatny.

Można też sprawdzić ręcznie:

uname -r
modprobe -n algif_aead 2>&1

Jeśli moduł daje się załadować i kernel jest z okresu 2017–2026 (przed fixem) — system jest podatny.


Źródła: copy.fail, Xint Code, NVD, CERT-EU, GitHub PoC