FlawOpen

flawopen.com/Teardowns/cve-2024-21626-runc-container-breakout-leaky-vessels

● CVE-2024-21626 · CVSS 8.6[1], [5] · Hoch
Sicherheitsforschung · FlawOpen

CVE-2024-21626: So behob runc den Leaky-Vessels-Ausbruch

CVE-2024-21626 verband ein internes Dateideskriptorleck in runc mit einer fehlenden Prüfung nach chdir. Je nach Startpfad konnte der Container mit einem Arbeitsverzeichnis im Host-Namespace starten oder über einen verwandten exec-Pfad Hostdateien erreichen.[1], [2], [3]

💡 Einfache Erklärung (ELI5)

runc richtet einen isolierten Raum für den Container ein. Ein internes Handle konnte das gewählte Arbeitsverzeichnis aus diesem Raum heraus auf den Host zeigen lassen; die abschließende Grenzprüfung und das Schließen interner Handles verhindern diese Übergabe.[1], [2]

Kernkonzepte & Begriffe

runc
Die OCI-Runtime zum Erstellen und Starten von Containern.[1]
Interner Dateideskriptor
Ein Betriebssystem-Handle für eine geöffnete Datei oder ein Verzeichnis. Ein offener, weitergereichter Deskriptor kann Zugriff über eine Prozessgrenze hinweg erhalten.[1], [3]
cwd
Das Arbeitsverzeichnis eines Prozesses. Linux kann bei Getwd ENOENT melden, wenn cwd außerhalb der Wurzel des Mount-Namespace liegt.[1], [2]
Container-Ausbruch
Ein Pfad, über den ein Containerprozess Hostressourcen außerhalb seiner Isolationsgrenze erreicht.[1]

Framework-Zuordnungen

  • CWE-Referenz für die in diesem Leitfaden beschriebene Schwachstelle: CWE-403

Ursachenanalyse

Vor runc 1.1.12 konnten interne Dateideskriptoren in runc init offengelegt werden. Sie waren intern für runc init und wurden nicht einfach an den Containerprozess vererbt. Bei Angriff 1 und 2 konnte das konfigurierte oder gewählte Arbeitsverzeichnis über ein Handle des Host-Mount-Namespaces aufgelöst werden; runc prüfte nach chdir nicht, ob das endgültige cwd innerhalb der Containerwurzel lag. Getrennte Varianten nutzten die execve-Pfadbehandlung, um eine Host-Binärdatei zu überschreiben. Version 1.1.12 ergänzte vier Schutzschichten: cwd-Prüfung mit Linux-Getwd/ENOENT-Verhalten, Schließen interner Deskriptoren unmittelbar vor execve, Behebung konkreter Lecks und close-on-exec für Nicht-stdio-Deskriptoren vor dem Start von runc init.[1], [2], [3], [4]

CVE-2024-21626: Angriffsvarianten und Schutzmaßnahmen in runc 1.1.12

Variante aus dem HinweisErforderliche Bedingungen und GrenzeRelevanter Fix oder Workaround
Angriff 1 — schädliches Image mit runc runEin privilegierter Nutzer muss zum Start eines nicht vertrauenswürdigen Images verleitet werden. Dessen konfiguriertes Arbeitsverzeichnis kann außerhalb des Mount-Namespace des Containers aufgelöst werden.Die Prüfung unix.Getwd() nach chdir schlägt fehl, wenn cwd außerhalb der Namespace-Wurzel liegt. Als vorübergehender Workaround darf cwd für nicht vertrauenswürdige Images nur / sein.
Angriff 2 — Containerprozess mit runc execEin Prozess im Container muss die Wahl eines cwd ungleich / durch einen Administrator mit runc exec --cwd vorhersehen und den relevanten Pfad vor dem Start vorbereiten.Dieselbe cwd-Prüfung nach chdir verhindert die Ausführung außerhalb des Containers. Bis zum Update --cwd auf / beschränken.
Angriff 3a — Überschreiben einer Host-Binärdatei beim Image-StartDiese Variante baut auf Angriff 1 auf und setzt weiterhin voraus, dass ein privilegierter Nutzer das schädliche Image startet; sie überschreitet die execve-Grenze zu einer Host-Binärdatei.Interne runc-Deskriptoren unmittelbar vor execve schließen, erkannte Lecks beheben und O_CLOEXEC setzen. Auf runc 1.1.12 oder eine vom Anbieter korrigierte Version aktualisieren.
Angriff 3b — Überschreiben einer Host-Binärdatei über runc execDiese Variante baut auf Angriff 2 auf und geht von einem schädlichen Prozess in einem laufenden Container aus, den der Angreifer beeinflussen kann; ein Administrator mit erhöhten Rechten muss dennoch einen normalen runc exec für diesen Container ausführen. Laut Hinweis ist dafür weniger Benutzerinteraktion nötig als beim Image-Pfad.Schließen vor execve und close-on-exec schützen diesen separaten Pfad. Die Maintainer nennen keinen praktikablen Workaround; aktualisieren.

Schritt-für-Schritt Angriffsablauf

Schritt 1

Internes Handle-Leck

Während der Vorbereitung konnte ein interner runc-Deskriptor mit Bezug zum Host-Mount-Namespace für runc init verfügbar bleiben.[1], [3]

Schritt 2

Erreichbarer Arbeitsverzeichnispfad

Ein schädliches Image oder ein runc-exec-Ablauf unter bestimmten Bedingungen konnte das angeforderte cwd außerhalb der Containerwurzel auflösen lassen.[1], [2]

Schritt 3

Grenzprüfung fehlte

Der frühere Code prüfte das endgültige cwd nach chdir nicht; verwandte Varianten missbrauchten die execve-Pfadbehandlung zum Überschreiben einer Host-Binärdatei.[2], [3]

Schritt 4

Auswirkung und Bedingungen

Der Hinweis dokumentiert Dateisystemzugriff und Hostkontrolle bei vier Varianten. Image-Angriffe erfordern, dass ein privilegierter Nutzer ein nicht vertrauenswürdiges Image startet. Angriff 3b setzt weiterhin voraus, dass ein Administrator einen normalen runc exec für einen Container ausführt, den der Angreifer beeinflussen kann.[1]

Quellcode: Verwundbar vs. Sicher

VERWUNDBARE IMPLEMENTIERUNG
// Vereinfachtes Verhalten vor dem Fix; kein wörtlicher runc-Quelltext
if err := os.Chdir(config.Cwd); err != nil {
    return err
}
// Es fehlte die Prüfung, ob das endgültige cwd innerhalb der Namespace-Wurzel liegt
GEHÄRTETER SICHERHEITS-PATCH
// Grenzprüfung aus runc 1.1.12 (Upstream-Auszug)
if wd, err := unix.Getwd(); errors.Is(err, unix.ENOENT) {
    return errors.New("cwd liegt außerhalb der Mount-Namespace-Wurzel des Containers")
} else if err != nil {
    return fmt.Errorf("cwd-Sicherheit kann nicht geprüft werden: %w", err)
} else if !filepath.IsAbs(wd) {
    return fmt.Errorf("cwd ist nicht absolut: %q", wd)
}

Checkliste für Engineering & Systemsicherheit

Quellen