
BPF-LSM-Mitigation für CVE-2026-31431 (Copy Fail) — verweigert die Erstellung von AF_ALG-Sockets clusterweit
BPF-LSM-Abschwächung für CVE-2026-31431 („Copy Fail“) und
die RxRPC-Variante von Dirty Frag sowie
für ähnliche Privilege-Escalation-Schwachstellen, die von Benutzerraum-Zugriff
auf einen kernelseitigen In-Place-Krypto-Pfad abhängen, der über die
Socket-Familien AF_ALG oder AF_RXRPC erreichbar ist.
Ein kleiner DaemonSet bindet ein einzelnes BPF-LSM-Programm an den
socket_create-Hook auf jedem Knoten. Das Programm gibt -EPERM für jeden
Benutzerraum-socket(AF_ALG, ...)- oder socket(AF_RXRPC, ...)-Aufruf
zurück, unabhängig von Prozess-Capabilities, Namespace oder Seccomp-Profil.
Kernelinterne sock_create_kern()-Aufrufer (z. B. fs/afs, der IPsec-Stack)
werden durchgelassen, sodass legitime Kernel-Benutzer weiterhin funktionieren.
Getestet auf Talos Linux (das seit v1.10 mit CONFIG_BPF_LSM=y und bpf im
Standard-LSM-Stack ausgeliefert wird), funktioniert auf jeder Distribution mit
derselben Kernel-Konfiguration.
Copy Fail (CVE-2026-31431) ist ein Logikfehler in algif_aead, der es
einem nicht privilegierten lokalen Benutzer ermöglicht, einen 4-Byte-Seitencache-
Schreibzugriff auf eine beliebige setuid-Binärdatei durchzuführen und mit einem
732-Byte-Python-Skript Root-Rechte zu erlangen. Der Exploit benötigt nichts
weiter als AF_ALG + splice(), beides ist standardmäßig von jedem nicht
privilegierten Prozess erreichbar. Der Mainline-Fix ist a664bf3d603d.
Dirty Frag ist eine Folge-Schwachstellenklasse, die im Mai 2026 von
derselben Forschungslinie offengelegt wurde. Sie verkettet zwei Bugs, die das
frag-Element von sk_buff „verschmutzen“ — xfrm-ESP Page-Cache Write und
RxRPC Page-Cache Write. Die RxRPC-Variante führt eine In-Place-pcbc(fcrypt)-
Entschlüsselung auf einer splice()-gepinnten Seitencache-Seite innerhalb von
rxkad_verify_packet_1() durch und erreicht Root, ohne dass eine
User-Namespace-Erstellung erforderlich ist, was sie zur universeller
ausnutzbaren Hälfte der Kette auf gehärteten Distributionen macht. Der
xfrm-ESP-Fix landete in netdev als f4c50a4034e6 (2026-05-07); Distributionen
portieren zum Zeitpunkt der Erstellung dieses Textes noch zurück, und für RxRPC
gibt es noch keinen öffentlichen Fix — siehe den
Upstream-Bericht
für den Offenlegungszeitplan.
Beide Exploits hängen vom Öffnen eines Sockets in der betroffenen Familie ab.
Bis die Kernel-Fixes in Ihrer Distribution eintreffen, kann die Angriffsfläche
entfernt werden, indem verhindert wird, dass Benutzerraum jemals AF_ALG- oder
AF_RXRPC-Sockets erstellt. Im Vergleich zu Alternativen:
| Abschwächung | Abdeckung | Neustart? | Bleibt bestehen? |
|---|---|---|---|
Kernel-Cmdline module_blacklist=af_alg,rxrpc (Familien-Handler, nicht nur algif_aead) | hostweit | ja | ja |
/etc/modprobe.d/*.conf mit install af_alg /bin/false + install rxrpc /bin/false und rmmod bereits geladener Module (entspricht der Upstream-Dirty-Frag-Anleitung — beachten Sie, dass ein einfaches blacklist das In-Kernel-request_module()-Autoload nicht stoppt, nur install … /bin/false tut das) | hostweit | nein | ja (solange die Datei vorhanden ist) |
Benutzerdefinierter Kernel ohne CRYPTO_USER_API / AF_RXRPC | hostweit | ja | ja |
| Benutzerdefiniertes Seccomp-Profil pro Pod | nur gekennzeichnete Workloads | nein | ja |
| copy-fail-blocker (dieses Projekt) | hostweiter Benutzerraum | nein | solange der DS läuft |
Dieses Projekt ist die Option ohne Neustart. Führen Sie es clusterweit aus und planen Sie dann die dauerhaften Kernel-Fixes in Ihrem normalen Patch-Rhythmus.
Hinweis zur ESP-Variante von Dirty Frag. Die
xfrm-ESP Page-Cache Write- Hälfte von Dirty Frag wird von diesem DaemonSet nicht geschlossen — sie wird über XFRM-Netlink +UDP_ENCAP_ESPINUDPausgelöst, nicht über eine dedizierte Socket-Familie, und ein sauberer BPF-LSM-Filter dafür würde entweder legitimes IPsec auf dem Host brechen oder eine User-Namespace-bewusste Logik erfordern. Derzeit nicht hier verfolgt — Beiträge willkommen. Auf gehärteten Distributionen, die nicht privilegierte User-Namespaces blockieren (z. B. Ubuntus Standard-AppArmor-Richtlinie), ist die ESP-Variante von vornherein unerreichbar und der RxRPC-Block hier ist ausreichend.
bpf/blocker.c ist ein kurzes BPF-LSM-Programm:
SEC("lsm/socket_create")
int BPF_PROG(block_socket_family, int family, int type, int protocol,
int kern, int ret)
{
if (ret)
return ret;
/* kern != 0 bedeutet sock_create_kern() — Kernel-Aufrufer durchlassen. */
if (!kern && (family == AF_ALG || family == AF_RXRPC)) // 38, 33
return -EPERM;
return 0;
}
Der Go-Loader (main.go, ~40 Zeilen) lädt das Programm und bindet es über
bpf(BPF_LINK_CREATE) an. Der Link wird für die Lebensdauer des Pods gehalten.
Bei SIGTERM wird der Link geschlossen und der Hook löst sich.
Erfordert einen Kernel, der mit CONFIG_BPF_LSM=y und bpf im aktiven LSM-
Stack (lsm=...,bpf in der Kernel-Befehlszeile) gebaut wurde. Talos Linux wird
seit v1.10 standardmäßig mit beidem ausgeliefert.
kubectl apply -f https://raw.githubusercontent.com/cozystack/copy-fail-blocker/v0.3.0/manifests/copy-fail-blocker.yaml
Für den neuesten Commit auf main (kann unveröffentlichte Änderungen enthalten):
kubectl apply -f https://raw.githubusercontent.com/cozystack/copy-fail-blocker/main/manifests/copy-fail-blocker.yaml
Das Chart ist nicht als OCI-Artefakt veröffentlicht (der Registry-Pfad wird mit dem Container-Image geteilt). Installation aus einem getaggten Checkout:
git clone --branch v0.3.0 https://github.com/cozystack/copy-fail-blocker
cd copy-fail-blocker
helm upgrade --install copy-fail-blocker charts/copy-fail-blocker \
--namespace kube-system
Oder über die Makefile-Verknüpfungen:
make apply # helm upgrade --install in kube-system
make diff # Änderungen gegen den Cluster anzeigen
make delete # Deinstallation
make manifest # manifests/copy-fail-blocker.yaml neu generieren
Der DaemonSet muss privilegiert laufen (er lädt BPF-Programme und schreibt in
bpffs). Platzieren Sie ihn in einem Namespace mit dem privilegierten
Pod-Security-Standard oder in kube-system, das standardmäßig privilegiert ist.
Von jedem Pod auf einem abgedeckten Knoten: