Linux-Kernel CVE-2026-80521: Der AF_UNIX-Garbage-Collector gibt einen Socket frei, den er noch in der Liste führt
Unix-Sockets können einander Dateideskriptoren zuschicken, sogar sich selbst, und so entstehen Kreise aus Sockets, die nur noch voneinander am Leben gehalten werden. Für solche Kreise hat der Linux-Kernel einen eigenen Garbage Collector, der seit Version 6.10 die Sockets als Graph verwaltet und gefundene Gruppen für den nächsten Durchlauf cacht. CVE-2026-80521 steckt in genau diesem Cache. Trifft der Collector ein schmales Zeitfenster zwischen Senden und Schließen, gibt er den Eintrag eines Sockets frei, der noch in einer gecachten Liste hängt, und der nächste Durchlauf greift auf freigegebenen Speicher zu. Weil jeder Standard-Container Unix-Sockets benutzen darf, wird daraus ein Weg vom unprivilegierten Prozess bis zu Root auf dem Host.
TL;DR — 90 Sekunden
- Was: Eine Race Condition im AF_UNIX-Garbage-Collector lässt einen freigegebenen Vertex, also den Eintrag eines Sockets im Graphen des Collectors, in einer gecachten Liste zurück. Der nächste Lauf des Collectors greift darauf zu, ein Use-after-free im Kernel.
- Schwere: CVSS 7.8 laut Kernel-CNA (
AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H), Amazon Linux und Red Hat kommen mit 7.0 etwas niedriger heraus. Seit dem 22. September gibt es einen öffentlichen Exploit, im CISA-KEV-Katalog steht die Lücke nicht. - Wen es trifft: Hosts mit Kerneln ab 6.10 sowie den Langzeitzweigen 6.1 ab 6.1.141 und 6.6 ab 6.6.93, solange der Fix fehlt. Die Schlagzeilen sprechen von Ubuntu, der Fehler steckt aber im Upstream-Kernel. Amazon Linux 2 ist nicht betroffen.
- Was zu tun ist: Den Kernel aktualisieren und die Nodes neu starten oder auf Amazon Linux 2023 den Livepatch einspielen und prüfen. Upstream behoben ist die Lücke in 6.1.189, 6.6.158, 6.12.111, 6.18.53 und 7.1.10 sowie in Mainline seit 7.2, also auch im neuen Linux 7.3 vom 18. Oktober.
- Was vorher geschützt hätte: Sandbox-Runtimes wie gVisor oder Kata Containers für fremden Code und eigene Node-Pools für CI und Mandanten. Standard-seccomp, entzogene Capabilities und User Namespaces helfen gegen diesen Mechanismus nicht.
Wie der Collector einen Socket-Eintrag zu früh freigibt
Über einen Unix-Socket kann ein Prozess mit der Control Message SCM_RIGHTS offene Dateideskriptoren an einen anderen Prozess schicken. Bis der Empfänger die Nachricht mit recvmsg() abholt, gilt ein solcher Deskriptor laut unix(7) als „in flight“. Er steckt dann in einem Socket-Puffer in der Empfangswarteschlange des Ziel-Sockets und hält die Datei, auf die er zeigt, am Leben. Das funktioniert auch mit Sockets selbst. Ein Socket lässt sich an sich selbst schicken, zwei Sockets können sich gegenseitig referenzieren, und schließt der Prozess danach alle seine Deskriptoren, bleibt ein Kreis übrig, den kein Prozess mehr erreicht und den die Referenzzählung nie auf null bringt.
Für diesen Fall hat der Kernel in net/unix/garbage.c einen eigenen Garbage Collector. Seit Linux 6.10 stellt er die Sockets als Graph dar, eingeführt von Kuniyuki Iwashima mit dem Commit 4090fa373f0e („af_unix: Replace garbage collection algorithm.“). Jeder Socket, der gerade Deskriptoren unterwegs hat, ist darin ein Vertex (struct unix_vertex). Jeder verschickte Deskriptor ist eine Edge (struct unix_edge), also ein Verweis von einem Socket auf einen anderen. Über diese Verweise sucht der Collector mit einem Verfahren nach Tarjan nach Strongly Connected Components, kurz SCC. Gemeint sind Gruppen von Sockets, die sich gegenseitig im Kreis referenzieren. Zeigt von außen nichts mehr auf eine solche Gruppe, ist sie tot, und der Collector räumt die Puffer ab, die sie zusammenhalten. Damit er nicht bei jedem Lauf den ganzen Graphen neu aufbauen muss, cacht er die gefundenen Gruppen in einer ringförmigen Liste über das Feld scc_entry. Spätere Läufe gehen über unix_walk_scc_fast() nur noch diese gecachten Listen ab, und laut Fix-Commit genügt schon ein weiterer Kreis im Graphen, um diesen schnellen Pfad zu erzwingen.
Genau hier lag der Fehler. Beim Senden trägt unix_add_edges() die neuen Edges in den Graphen ein. Dafür nimmt die Funktion kurz den Lock unix_gc_lock und gibt ihn gleich wieder frei. Erst danach hängt skb_queue_tail() den Puffer mit den Deskriptoren in die Warteschlange. Zwischen beiden Schritten liegt ein kurzes Zeitfenster, und genau darin entsteht die Race Condition. Der Fix-Commit spielt den Ablauf an einem kleinen Beispiel durch. Ein Socket X verweist auf sich selbst, zwei Sockets A und B referenzieren sich gegenseitig. Während ein Thread über X den Socket B an B selbst schickt, schließt ein anderer A und B. Erwischt der Collector genau dieses Zeitfenster, sieht er die neue Edge von B auf B schon, den zugehörigen Puffer aber noch nicht. Er hält A und B für tot, kann den Puffer jedoch nicht einsammeln, weil der noch in keiner Warteschlange liegt, und so überlebt B vorerst.
Für sich genommen wäre das harmlos, denn der nächste Lauf würde auch B als tot erkennen. Das Problem entsteht beim Aufräumen. Verwirft der Collector Puffer, entfernt unix_del_edge() die zugehörigen Edges, und ein Vertex, von dem keine Edge mehr ausgeht, wandert auf eine Liste zum Freigeben. Aus der gecachten Liste scc_entry nahm ihn bis zum Fix aber niemand heraus. Die Liste des überlebenden B zeigt deshalb weiter auf den Speicher von A, und weil der Kreis von X den nächsten Lauf in den schnellen Pfad zwingt, folgt unix_walk_scc_fast() diesem Zeiger in freigegebenen Speicher. Das ist das klassische Muster eines Use-after-free. Wer den frei gewordenen Speicher vorher mit eigenen Daten belegt, bestimmt, mit welchen Werten der Kernel weiterarbeitet.
Gefährlich wird der Fehler durch zwei Eigenschaften des Designs. Der Collector läuft im Kernel, angestoßen von gewöhnlichen Socket-Operationen, die jeder Prozess ausführen darf. Und das Zeitfenster öffnet sich bei jedem Sendevorgang neu, sodass ein Angreifer es so oft anlaufen kann, bis die Race Condition einmal greift. Besondere Rechte oder exotische Kernel-Funktionen braucht er dafür nicht.
Was der Fix-Commit ändert
Der Fix-Commit 594d90519502 stammt ebenfalls von Kuniyuki Iwashima, gemeldet und geprüft hat ihn Kyle Zeng. Er besteht aus einer einzigen Zeile in net/unix/garbage.c. In unix_del_edge() ruft der Zweig, der einen Vertex ohne ausgehende Edges auf die Freigabeliste verschiebt, jetzt zusätzlich list_del(&vertex->scc_entry) auf. Bisher wurde der Vertex dort nur in eine andere Liste umgehängt und blieb in der gecachten Liste seiner Gruppe eingetragen. Jetzt verlässt er beim Abräumen beide Listen, und kein Cache-Eintrag kann mehr auf ihn zeigen. Das Fixes-Tag verweist auf 4090fa373f0e, also genau auf den Umbau, mit dem der Fehler entstanden ist.
Bemerkenswert finde ich, was der Fix nicht ändert. Das Zeitfenster zwischen unix_add_edges() und skb_queue_tail() bleibt bestehen, und der Commit nennt den vorübergehend überlebenden Socket ausdrücklich unproblematisch. Die Ursache war also kein fehlender Lock, sondern ein Cache, der länger lebte als die Objekte, auf die er zeigte. Daraus leite ich eine allgemeine Regel ab: Jede Optimierung, die Ergebnisse eines Laufs für den nächsten aufhebt, schafft einen zweiten Ort, an dem ein Objekt registriert ist, und jeder Freigabepfad muss beide Orte kennen.
Dass der neue Collector auch zwei Jahre nach seinem Einzug noch Feinarbeit braucht, zeigen zwei weitere Korrekturen. Mit den Stable-Releases vom 3. Oktober kam ein zweiter Use-after-free-Fix in die Langzeitzweige („af_unix: Drop all SCM attributes for SOCKMAP.“), dessen Ursache die Annahme war, das Ziel einer Edge sei immer noch am Leben. Das am 18. Oktober erschienene Linux 7.3 enthält außerdem „af_unix: Unify scc_index when finalising SCC in __unix_walk_scc().“, das zuvor schon in 6.18.54 zurückportiert wurde. Laut Commit konnte eine Gruppe, in der mehrere Verweise zurückführen, je nach Reihenfolge des Durchlaufs unterschiedliche Indizes tragen, sodass der Collector sie nicht als tot erkannte und nie freigab. Eine CVE nennt dieser Commit nicht.
Vom Container-Prozess zu Root auf dem Host
Für einen Angriff genügt lokale Codeausführung auf einem Host mit verwundbarem Kernel. Die nötigen Aufrufe gehören zum Alltag jedes Programms: Unix-Sockets anlegen, Deskriptoren per SCM_RIGHTS verschicken und Sockets schließen, verteilt auf mehrere Threads. Die Standard-seccomp-Profile von Docker und Kubernetes erlauben all das, und Capabilities braucht es nicht, was die CVSS-Bewertung mit PR:L ausdrückt. Ein gewöhnlicher Container ab Werk ist also betroffen, sobald der Kernel seines Nodes verwundbar ist.
Konzeptionell verläuft der Angriff in drei Schritten. Zuerst löst der Angreifer die Race Condition so oft aus, bis der Collector einen Vertex freigibt, der in der gecachten Liste hängen bleibt. Dann belegt er den frei gewordenen Speicher neu, damit der nächste Lauf mit Daten arbeitet, die er bestimmt. Am Ende steht nach Angaben von DepthFirst und bex.co eine Root-Shell auf dem Host, die Namespaces, cgroups und seccomp hinter sich lässt. Eine Grenze zwischen Container und Host muss dieser Pfad dabei gar nicht überwinden, denn alle Container eines Nodes teilen sich denselben Kernel.
Wie groß der Schaden wird, hängt davon ab, was auf dem Node liegt. Root auf einem Kubernetes-Node bedeutet Zugriff auf alle Container dieses Nodes, auf ihre gemounteten Secrets und ServiceAccount-Tokens und auf die Zugangsdaten des Kubelets. Auf EC2 kommt die Instanzrolle hinzu, deren Credentials der Host über den Metadatendienst abrufen kann. Besonders exponiert sind Nodes, auf denen fremder Code läuft, etwa CI-Runner für Merge Requests aus Forks, Cluster mit mehreren Mandanten oder Dienste, die Code von Nutzern ausführen. Doch auch ohne fremden Code kann die Lücke zum zweiten Glied einer Kette werden, zum Beispiel nach einer Codeausführung in einer Web-Anwendung, wie sie TYPO3-Extensions in diesem Jahr mehrfach erlaubten.
In der Berichterstattung erschien die Lücke als Ubuntu-Problem. Das liegt am öffentlichen Exploit, der einen bestimmten Kernel von Ubuntu 26.04 angreift, und daran, dass Canonical für Ubuntu 24.04 und 26.04 noch keinen Fix ausgeliefert hat. Der Tracker steht seit dem 13. Oktober unverändert. Diese Lesart führt aber in beide Richtungen in die Irre. Der Fehler steckt im Upstream-Code und damit in jedem Kernel mit dem neuen Collector, also in Mainline ab 6.10 und in den Langzeitzweigen 6.1 ab 6.1.141 und 6.6 ab 6.6.93, in die der Umbau zurückportiert wurde. Ältere Zweige ohne diesen Backport sind nicht betroffen. Für Amazon Linux 2 meldet ALAS alle Kernel-Varianten als nicht betroffen, den Core-Kernel ebenso wie die Extras 5.4, 5.10 und 5.15, und dasselbe gilt für Debian 11. Ein auf einen Ubuntu-Build zugeschnittener Exploit läuft auf anderen Kerneln zwar nicht ohne Anpassung, der Mechanismus bleibt aber derselbe.
| CVE | Betroffen | Fix | Voraussetzung | CVSS |
|---|---|---|---|---|
| CVE-2026-80521 | Linux ab 6.10, 6.1 ab 6.1.141 und 6.6 ab 6.6.93 (Backport des neuen Collectors) | Upstream 594d90519502; 6.1.189, 6.6.158, 6.12.111, 6.18.53, 7.1.10, Mainline ab 7.2 (auch 7.3) | Lokale Codeausführung, Unix-Sockets mit SCM_RIGHTS, in Standard-Containern erlaubt | 7.8 (hoch) laut CNA, 7.0 laut AWS und Red Hat |
Bei der Bewertung gehen die Quellen leicht auseinander. Der Kernel-CNA vergibt 7.8, während Amazon Linux und Red Hat die Angriffskomplexität wegen der Race Condition auf hoch setzen und auf 7.0 kommen. Red Hat stuft die Lücke zudem nur als Moderate ein. Am Mechanismus ändert das nichts. DepthFirst setzte den Exploit am 24. Juli in Googles kernelCTF gegen das Ziel lts-6.12.95 ein, am 5. August wurde der Gewinn des Slots bestätigt, und am 22. September veröffentlichte das Team Analyse und Exploit-Code. Ausnutzung in freier Wildbahn ist bisher nicht bekannt, im CISA-KEV-Katalog steht die Lücke nicht, und EPSS schätzt die Wahrscheinlichkeit einer Ausnutzung in den nächsten 30 Tagen auf 0,17 Prozent. Da öffentlicher Code für eine verbreitete Distribution existiert, halte ich diese Zahl eher für eine Untergrenze.
Kernel-Fix, Livepatch und der Weg auf die Nodes
Upstream ist die Lücke seit dem 6. August behoben. In Mainline steckt der Fix seit 7.2, in den Stable-Zweigen seit 6.12.111, 6.18.53 und 7.1.10 und in den Langzeitzweigen seit 6.1.189 und 6.6.158, die am 3. Oktober erschienen sind. Das Linux 7.3 vom 18. Oktober enthält ihn damit ebenfalls. Für diese Lücke musst du aber nicht auf 7.3 wechseln, denn auch die aktuellen Stable-Kernel vom 15. Oktober, 6.1.190, 6.6.159, 6.12.113 und 6.18.57, sind gefixt. Einen Kernel selbst zu bauen ist für Produktionssysteme selten der richtige Weg. Maßgeblich ist das Kernel-Paket deiner Distribution.
Für Amazon Linux 2023 hat AWS am 30. September alle drei Kernel-Pakete aktualisiert: kernel auf 6.1.188-233.386.amzn2023 (ALAS2023-2026-3146), kernel6.12 auf 6.12.110-135.202.amzn2023 (ALAS2023-2026-3147) und kernel6.18 auf 6.18.51-120.163.amzn2023 (ALAS2023-2026-3148). Gezielt spielst du ein solches Update laut Advisory etwa mit dnf update --advisory ALAS2023-2026-3147 --releasever 2023.12.20260930 ein, für die anderen Pakete mit der jeweiligen Advisory-ID. Am selben Tag erschienen Livepatches für die Reihen 6.1, 6.12 und 6.18 (ALAS2023LIVEPATCH-2026-389 bis -423).
Debian hat den Fix für Debian 13 mit 6.12.111-1 (DSA-6528-1) und für Debian 12 mit 6.1.190-1 (DLA-4841-1) ausgeliefert. Bei Wolfi gibt es dagegen nichts zu patchen, denn laut Chainguard baut Wolfi keinen eigenen Kernel und nutzt den der Umgebung. Ein Update deiner Wolfi- oder Chainguard-Images ändert an dieser Lücke also nichts, gepatcht wird allein der Host.
Der Livepatch ist auf Amazon Linux 2023 der schnellste Weg, setzt aber einiges voraus. Laut AWS-Doku ist Kernel Live Patching ab Werk ausgeschaltet. Du aktivierst es mit dem DNF-Plugin kpatch-dnf und dem Befehl sudo dnf kernel-livepatch -y auto und startest anschließend den Dienst kpatch.service aus dem Paket kpatch-runtime. Livepatches liefert AWS für eine Kernelversion nur drei Monate lang und nur nach bestem Bemühen, und die angezeigte Kernelversion ändert sich erst nach einem Neustart. Ob der Patch wirklich geladen ist, zeigt sudo kpatch list. Genau das solltest du prüfen, statt aus dem installierten Paket auf Schutz zu schließen.
Die häufigste Stolperfalle ist der Unterschied zwischen installiertem und laufendem Kernel. Ein Paketupdate wirkt erst nach dem Neustart, auf Kubernetes-Nodes also erst, wenn du den Node absperrst, leerst und neu startest oder gleich durch einen Node aus einem aktuellen Image ersetzt. Wer Node-Images selbst baut oder fertige AMIs bezieht, braucht ein Image mit gefixtem Kernel und einen Rollout über alle Node-Gruppen. Der Fix selbst bringt keine funktionalen Breaking Changes mit, er ist nur eine Zeile. Das Risiko steckt eher im Kernel-Update als Ganzem, das bei einem Stable-Sprung viele weitere Änderungen enthält. Deshalb gehört auch ein Sicherheits-Kernel zuerst auf Staging-Nodes.
Härtung gegen einen Fehler im gemeinsamen Kernel
Bevor es um einzelne Maßnahmen geht, lohnt eine Einordnung. Der Angreifer nutzt keine Rechte, die man ihm entziehen könnte, sondern Systemaufrufe, die praktisch jedes Programm braucht, und der fehlerhafte Code läuft im Kernel, den sich alle Container eines Nodes teilen. Wirksam sind deshalb nur Maßnahmen, die an einer von drei Stellen ansetzen: Fremder Code bekommt den Host-Kernel gar nicht erst zu sehen, die Angriffsfläche einzelner Workloads wird gezielt verkleinert, oder ein gelungener Ausbruch trifft nur einen Node mit wenig Wert. Hinzu kommt die Geschwindigkeit, mit der ein Fix auf jedem Node ankommt.
gVisor als Sandbox für fremden Code
gVisor schiebt zwischen Anwendung und Host einen eigenen Kernel im Userspace, den Sentry. Laut Sicherheitsmodell des Projekts reicht der Sentry keinen Systemaufruf der Anwendung direkt an den Host weiter, sondern implementiert die Schnittstelle selbst. Neue Sockets auf dem Host darf er ohne Host-Networking nicht anlegen. Die Unix-Sockets einer Anwendung in gVisor erreichen den Collector des Host-Kernels also nie, und genau damit begründet auch die Analyse von bex.co, warum gVisor hier schützt. In Kubernetes bindest du gVisor über eine RuntimeClass ein. In containerd registrierst du dafür einen Runtime-Handler runsc mit runtime_type = "io.containerd.runsc.v1", legst eine RuntimeClass mit handler: runsc an und setzt in den Pods runtimeClassName. Über scheduling.nodeSelector der RuntimeClass sorgst du dafür, dass solche Pods nur auf Nodes landen, auf denen gVisor installiert ist.
Die Grenzen sind bekannt. gVisor implementiert nicht jeden Systemaufruf, und I/O-lastige Jobs laufen langsamer, deshalb testest du jede Workload vorher. Für CI ist gVisor trotzdem oft der beste Hebel. Der GitLab Runner mit Kubernetes-Executor kennt in [runners.kubernetes] den Schlüssel runtime_class_name, der für alle Job-Pods eine RuntimeClass setzt. Zusammen mit node_selector und node_tolerations laufen Merge Requests aus fremden Forks dann in einer Sandbox auf eigenen Nodes.
Kata Containers und microVMs
Kata Containers geht einen Schritt weiter und startet jeden Pod in einer leichtgewichtigen virtuellen Maschine mit eigenem Kernel, isoliert über Hardware-Virtualisierung. Enthält der Gast-Kernel denselben Fehler, ist er zwar ebenfalls angreifbar. Ein gelungener Ausbruch endet dann aber in der VM und nicht auf dem Host, und für die Trennung von Mandanten ist genau das der entscheidende Unterschied. DepthFirst empfiehlt diese Klasse, also Firecracker oder Kata, ausdrücklich für Workloads, denen du nicht traust. Der Preis ist ein höherer Ressourcenbedarf pro Pod, den du in der RuntimeClass über overhead.podFixed einplanst.
Außerdem müssen deine Nodes selbst virtuelle Maschinen starten können. Auf EC2 war das lange ein Hindernis, weil der Node dort schon in einer VM läuft, und AWS empfahl für Kata deshalb Bare-Metal-Instanzen wie i3.metal. Seit Februar 2026 unterstützt EC2 laut AWS-Doku verschachtelte Virtualisierung mit KVM als Hypervisor, derzeit auf den Familien M7i, M8i, C7i, C8i, R7i, R8i, X8i, I7i und I7ie samt ihren Varianten. Du schaltest sie pro Instanz über die CPU-Option NestedVirtualization=enabled ein, ohne Aufpreis, und ob ein Instanztyp sie beherrscht, zeigt aws ec2 describe-instance-types mit dem Feature nested-virtualization. Für leistungs- oder latenzkritische Workloads rät AWS weiterhin zu Bare Metal. Hypervisor und Gast-Kernel in der Instanz fallen nach dem Modell der geteilten Verantwortung in deine Zuständigkeit. Einen Zielkonflikt will ich dabei offen nennen: Vercel empfiehlt nach PwnEscape für Sandbox-Hosts ausdrücklich, Nested Virtualization abzuschalten. Wer sie für Kata einschaltet, holt sich bewusst eine weitere Virtualisierungsschicht mit eigener Angriffsfläche ins Haus, die genauso aktuell gehalten werden muss wie der Kernel.
Die Liste enthält ausschließlich Intel-Instanzen. Graviton-Familien wie c7g, m7g oder r7g fehlen, wer dort Kata einsetzen will, bleibt also auf Bare-Metal-Instanzen angewiesen. Für Cluster auf Graviton ist gVisor deshalb oft der naheliegendere Weg, weil es keine Hardware-Virtualisierung voraussetzt.
Eigene Node-Pools für Code, dem du nicht traust
Wo keine Sandbox möglich ist, kommt es darauf an, was ein Angreifer nach dem Ausbruch vorfindet. Root auf einem Node heißt Zugriff auf alle Pods dieses Nodes und auf die Identität des Kubelets. Der Node-Autorisierer von Kubernetes erlaubt dem Kubelet allerdings nur, Secrets, ConfigMaps und Volumes der Pods zu lesen, die auf seinem Node laufen, und das Admission-Plugin NodeRestriction hindert es daran, fremde Node- und Pod-Objekte zu ändern. Ein Ausbruch auf einem CI-Node erreicht deshalb nicht automatisch die Datenbank-Zugangsdaten deiner Produktion, solange beide nie auf demselben Node laufen. Diese Trennung setzt du mit Taints auf eigenen Node-Pools durch, deren passende Tolerations nur CI-Jobs oder Mandanten-Workloads tragen. Prüfe dabei, ob dein API-Server den Node-Autorisierer und NodeRestriction tatsächlich aktiviert hat. Auf EC2 gehört dazu eine eng geschnittene Instanzrolle für diese Nodes, denn auch sie erreicht, wer Root auf dem Host hat. Als kurzfristige Lösung nennt bex.co außerdem einen Node-Pool auf einem nicht betroffenen Kernel, mit dem Nachteil, dass dieser Kernel älter ist.
seccomp-Sperre für AF_UNIX in einzelnen Workloads
Ein eigenes seccomp-Profil kann Unix-Sockets sperren, allerdings nur grob. Laut Kernel-Dokumentation sehen seccomp-Filter nur die Argumente eines Systemaufrufs und dürfen keine Zeiger dereferenzieren. Die Adressfamilie ist bei socket() und socketpair() das erste Argument, eine einfache Zahl, und lässt sich deshalb filtern. Die Control Message mit SCM_RIGHTS steckt dagegen in einer Struktur im Speicher des Prozesses, von der sendmsg() nur einen Zeiger erhält. Mit seccomp lässt sich also nicht gezielt das Weiterreichen von Deskriptoren verbieten, sondern nur Unix-Sockets als Ganzes.
Das bricht allerdings viele Programme. Namensauflösung über NSS, Datenbank-Clients mit lokalen Sockets, Prozessmanager, Logging und viele Laufzeitumgebungen brauchen Unix-Sockets, häufig auch PHP-FPM hinter einem Webserver im selben Pod. Für einen einzelnen, getesteten Dienst, der nachweislich ohne sie auskommt, ist ein Profil mit seccompProfile.type: Localhost und localhostProfile eine Option. Als Maßnahme für die ganze Flotte taugt es nicht.
Patch-Geschwindigkeit als Härtung
Zwischen Upstream-Fix und öffentlichem Exploit lagen sieben Wochen, und manche Distributionen hatten auch danach noch nicht nachgezogen. Bei Kernel-Lücken ist der Weg vom Advisory bis zum laufenden Kernel auf jedem Node deshalb selbst eine Sicherheitsmaßnahme. Auf Amazon Linux 2023 gehört Kernel Live Patching eingeschaltet und überwacht, weil es die Zeit bis zum nächsten Wartungsfenster überbrückt. Den Rest der Lücke verkürzt du, indem du Nodes regelmäßig aus aktuellen Images ersetzt, statt sie lange am Leben zu halten.
Was hier nicht hilft
Die Standard-seccomp-Profile mit RuntimeDefault erlauben Unix-Sockets und das Weiterreichen von Deskriptoren. Weil der Pod Security Standard „restricted“ genau dieses Profil verlangt, ändert auch er hier nichts. Entzogene Capabilities und runAsNonRoot greifen nicht, denn der Angriff braucht keine Rechte. allowPrivilegeEscalation: false setzt no_new_privs, was laut Kernel-Doku nur verhindert, dass ein execve() neue Rechte verleiht, und gegen einen Speicherfehler im Kernel nichts ausrichtet. readOnlyRootFilesystem schützt das Dateisystem des Containers, der Angriff spielt sich aber im Kernelspeicher ab.
Auch User Namespaces und rootless Container ändern laut bex.co nichts an der Ausnutzbarkeit, und Updates von runc, containerd oder Docker helfen nicht, weil der Fehler im Host-Kernel sitzt. NetworkPolicies und Egress-Sperren laufen ebenfalls ins Leere, denn der Angriff ist rein lokal. Ein minimales Base-Image wie Wolfi nimmt einem Angreifer zwar Werkzeuge weg, enthält aber keinen Kernel. Ein CVE-Gate, das nur Container-Images scannt, findet diese Lücke deshalb nie. Kernel-CVEs tauchen erst auf, wenn du die Nodes selbst scannst.
Mehr zu Node-Isolation, Pod Security und Mandantentrennung findest du in der Serie TYPO3 auf Kubernetes unter IT-Grundschutz.
Erkennung und Prüfung
Ob ein Node betroffen ist, klärst du in zwei Schritten. Zuerst zeigt uname -r den laufenden Kernel, den du mit dem Tracker deiner Distribution vergleichst, bei Amazon Linux also mit ALAS und bei Debian mit dem Debian Security Tracker. Ob der neue Collector überhaupt im Kernel steckt, verrät laut bex.co der Befehl grep -cE ' unix_(add|del)_edges$' /proc/kallsyms. Liefert er einen Wert über null, ist der Graph-basierte Collector vorhanden, und dann zählt das Urteil des Trackers, nicht die Versionsnummer allein. Weil sich alle Container den Kernel teilen, funktioniert diese Prüfung laut derselben Quelle auch aus einem gewöhnlichen Container heraus, sofern die Datei dort nicht gesperrt ist. In gVisor- oder Kata-Sandboxen sagt sie dagegen nichts über den Host. Auf Amazon Linux 2023 zeigt dir sudo dnf updateinfo list cves die verfügbaren Korrekturen und sudo kpatch list die geladenen Livepatches.
Einen Angriff nachzuweisen ist deutlich schwieriger. Weder DepthFirst noch die Distributionen veröffentlichen Indikatoren, und eine gelungene Ausnutzung hinterlässt keine eindeutige Spur. Aus der Art des Fehlers leite ich einen Anhaltspunkt ab: Fehlgeschlagene Versuche an einem Use-after-free können den Kernel aus dem Tritt bringen. Oops-Meldungen oder unerwartete Neustarts von Nodes, in deren Stacktrace Funktionen aus net/unix/garbage.c auftauchen, verdienen deshalb einen zweiten Blick, auch wenn sie kein Beweis sind. Aussagekräftiger ist meist, was nach einem Ausbruch passiert, etwa Prozesse auf dem Host, die keinem bekannten Dienst gehören, oder Anfragen mit der Identität eines Kubelets im Audit-Log, die nicht von dessen Node kommen.
Bei einem Verdacht behandelst du den Node als kompromittiert. Sperre ihn für neue Pods und sichere Speicher und Logs, bevor du ihn neu startest. Danach ersetzt du ihn durch einen frischen Node mit gefixtem Kernel, statt ihn zu reparieren, und rotierst alle Secrets und Tokens der Pods, die dort liefen, die Zugangsdaten des Kubelets sowie auf EC2 die aktiven Sitzungen der Instanzrolle.
Betreiberempfehlung
Akut handeln solltest du, wenn deine Nodes einen Kernel mit dem neuen Collector ohne Fix fahren und dort Code läuft, den du nicht vollständig kontrollierst. Das betrifft CI-Runner für externe Merge Requests, Cluster mit mehreren Mandanten und Dienste, die Nutzercode ausführen, aber auch Web-Anwendungen mit großer Angriffsfläche, bei denen eine Codeausführung nur eine Extension-Lücke entfernt ist. Spiel dann sofort Livepatch oder Kernel-Update ein, rolle die Nodes neu aus und verschiebe fremden Code bis dahin auf Nodes mit Sandbox oder gefixtem Kernel.
Beobachten genügt, wenn deine Hosts nicht betroffen sind, etwa auf Amazon Linux 2 oder auf Kerneln vor 6.10 ohne den Backport, oder wenn der Fix bereits läuft und du ihn mit uname -r und bei Livepatches mit kpatch list belegt hast. Die Entscheidung, welche Workloads eine Sandbox brauchen, solltest du trotzdem treffen, denn diese Lücke ist in diesem Jahr nicht der erste Ausbruch über den Kernel, wie schon GhostLock gezeigt hat.
Unabhängig vom Einzelfall gilt, was ich bei jeder Lücke sage: Patches und Updates gehören automatisiert, und bei Kernel-Lücken heißt das Node-Images und Host-Pakete. Wenn Renovate oder Dependabot neue Versionen deiner Node-Images und Helm-Charts in deinem OpenTofu-Code als Merge Request vorschlagen und die Pipeline den neuen Kernel zuerst auf Staging-Nodes ausrollt und testet, ist ein Sicherheits-Kernel wie dieser eine Sache von Stunden statt Wochen. Eine Karenzzeit für Routine-Updates schützt vor kompromittierten Releases, Sicherheitsupdates nimmst du davon aus. Bringt ein Stable-Sprung im Kernel einen Breaking Change mit, etwa bei Treibern oder Netzwerkfunktionen, fällt er im Test auf und nicht erst in Produktion. Wer Nodes dagegen von Hand aktualisiert, betreibt in der Urlaubszeit schnell vier Wochen lang einen Kernel mit öffentlichem Exploit und steht danach vor einem Sammel-Update, bei dem alle Nodes gleichzeitig neu starten müssen.
Häufige Fragen zu CVE-2026-80521
Ich nutze kein Ubuntu. Bin ich trotzdem betroffen?+
Ja, wenn dein Kernel den neuen Collector enthält und noch keinen Fix hat. Das gilt ab 6.10 sowie für 6.1 ab 6.1.141 und 6.6 ab 6.6.93. Der Fehler steckt im Upstream-Kernel, nicht in Ubuntu.
Warum blockiert seccomp den Angriff nicht?+
Das Standardprofil erlaubt Unix-Sockets und das Weiterreichen von Deskriptoren. Ein eigenes Profil kann nur Unix-Sockets als Ganzes sperren, weil seccomp den Inhalt von sendmsg() nicht lesen kann. Das bricht viele Anwendungen.
Hilft ein minimales Image wie Wolfi?+
Nein. Wolfi enthält keinen eigenen Kernel, jeder Container nutzt den Kernel des Hosts. Ein Image-Update ändert an der Lücke nichts, gepatcht wird nur der Node.
Reicht der Livepatch auf Amazon Linux 2023?+
Er schließt diese Lücke, wenn er wirklich geladen ist. Prüfe das mit sudo kpatch list. Livepatches gibt es pro Kernel nur drei Monate, den Neustart in den gefixten Kernel planst du trotzdem ein.
Was ist mit Amazon Linux 2?+
Laut ALAS sind alle Kernel von Amazon Linux 2 nicht betroffen, der Core-Kernel ebenso wie die Extras 5.4, 5.10 und 5.15. Der neue Collector steckt dort nicht drin. Amazon Linux 2023 ist dagegen betroffen und seit dem 30. September gefixt.
Fazit
CVE-2026-80521 ist ein kleiner Fehler mit großer Reichweite. Eine fehlende Zeile im Freigabepfad eines Caches genügt, damit ein Prozess ohne jede Berechtigung aus seinem Container ausbricht. Die übertragbare Lehre liegt weniger im Kernel-Code als in der Architektur. Alles, was die Rechte innerhalb eines Containers beschneidet, schützt nicht vor Fehlern in Systemaufrufen, die jeder Container benutzen darf, und der Kernel bleibt die gemeinsame Angriffsfläche aller Pods eines Nodes. Für Code, dem du nicht traust, solltest du deshalb bewusst entscheiden, welche Isolationsklasse er bekommt, und nicht nur, welche Capabilities. Wie schon bei GhostLock und PwnEscape entscheidet am Ende die Zeit, die ein gefixter Kernel braucht, bis er auf jedem Node läuft.
Quellen
- Linux-Kernel: Fix-Commit 594d90519502 „af_unix: Unlink scc_entry in unix_del_edge().“
- Linux-Stable: Backport für 6.1.y (2b6c2842692d)
- Linux-Stable: Backport für 6.6.y (6fda5c51b8e4)
- Linux-Kernel: Commit 4090fa373f0e „af_unix: Replace garbage collection algorithm.“
- kernel.org: ChangeLog Linux 7.3 (18. Oktober 2026)
- kernel.org: ChangeLog Linux 6.18.54
- DepthFirst: Containers are no longer safe (Analyse des Entdeckers)
- bex.co: CVE-2026-80521 und die Patch-Lücke
- OpenCVE: CVE-2026-80521 (CNA-Daten, CVSS, EPSS)
- Amazon Linux Security Center: CVE-2026-80521
- ALAS2023-2026-3146 (kernel)
- ALAS2023-2026-3147 (kernel6.12)
- ALAS2023-2026-3148 (kernel6.18)
- Debian Security Tracker: CVE-2026-80521
- AWS: Kernel Live Patching on AL2023
- man7: unix(7)
- Kernel-Doku: Seccomp BPF
- Kernel-Doku: No New Privileges Flag
- gVisor: Security Model
- gVisor: containerd Quick Start
- Kubernetes Docs: Runtime Class
- Kubernetes Docs: Node Authorization
- Kata Containers
- AWS: Nested virtualization auf EC2
- AWS Containers Blog: Kata Containers auf EKS
- GitLab Runner: Kubernetes executor
- Chainguard: Wolfi Overview
Ich prüfe, welche deiner Nodes fremden Code auf einem verwundbaren Kernel ausführen, richte Sandbox-Runtimes für CI und Mandanten ein und automatisiere den Kernel-Rollout bis zum letzten Node.
Kernel- und Node-Audits für Kubernetes und EC2, gVisor- und Kata-RuntimeClasses für GitLab-Runner und Mandanten-Workloads, Livepatching und automatisierte Node-Rotation mit getesteten Pipelines.
Plattform-Betrieb statt Beratung auf Papier: Ich prüfe, patche und härte deine Infrastruktur laufend.
