FlawOpen

flawopen.com/Teardowns/cve-2024-26585-linux-tls-tx-work-close-race

● CVE-2024-26585 · CVSS 4.7 · Mittel
Sicherheitsforschung · FlawOpen

CVE-2024-26585: TLS-Schließrace im Linux-Kernel

Bei Linux-kTLS konnte der Abschluss sendmsg/recvmsg wecken, bevor TX-Arbeit eingereiht war. Der Fix reiht die Arbeit zuerst ein.

💡 Einfache Erklärung (ELI5)

Ein Mitarbeiter sagt einem wartenden Kollegen „fertig“, bevor er seine letzte Aufgabe in die gemeinsame Warteschlange legt. In der Lücke kann der Kollege den Betrieb schließen und vorhandene Aufgaben abbrechen; danach stellt der Mitarbeiter noch eine Aufgabe ein. Der Kernel-Fix reiht TLS-Sendearbeit ein, bevor er den Abschluss signalisiert.

Kernkonzepte & Begriffe

kTLS
TLS im Linux-Kernel, das TLS-Datensätze im Netzwerkpfad des Kernels verarbeitet.
Asynchroner Kryptoabschluss
Callback, der nach Abschluss einer asynchronen TLS-Verschlüsselung ausgeführt wird.
`complete()`
Linux-Completion-Primitive, die einen auf das Ende eines Vorgangs wartenden Thread weckt.
Verzögerte TX-Arbeit
Eingereihte Kernel-Arbeit, die die TLS-Datenübertragung nach der Verschlüsselung fortsetzt.

Framework-Zuordnungen

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

Ursachenanalyse

In net/tls/tls_sw.c konnte tls_encrypt_done() complete() für den auf sendmsg()/recvmsg() wartenden Thread aufrufen, bevor die verzögerte TX-Arbeit für den ersten Datensatz geplant wurde. Der geweckte Thread kann zurückkehren und den Socket schließen, während der Callback die Arbeit noch einreiht. Dadurch konkurrieren Socket-Schließung und TX-Arbeitsplanung. Der Upstream-Commit e01e3934a1b2 kehrt die Reihenfolge um: Liegt der Datensatz am Anfang von ctx->tx_list, wird ctx->tx_work vor dem Aufruf von complete() geplant. Die CVE-Mitteilung beschreibt eine Race Condition; die zitierten Quellen belegen nicht die früheren Aussagen zu MSG_ZEROCOPY, freigegebenen Netzwerkseiten, Überschreiben oder einem Fix mit refcount_inc_not_zero().

Schritt-für-Schritt Angriffsablauf

Schritt 1

1. TLS-Übertragung beginnt

Ein Prozess nutzt den kTLS-Sendepfad, auf dem Datensatzverschlüsselung asynchron enden kann.

Schritt 2

2. Callback prüft die Reihenfolge

tls_encrypt_done() prüft, ob der abgeschlossene Datensatz am Anfang von ctx->tx_list steht.

Schritt 3

3. Wecken konkurriert mit dem Schließen

Vor dem Patch konnte der Callback den Thread mit complete() wecken und TX-Arbeit erst danach einreihen; dazwischen konnte der Thread den Socket schließen.

Schritt 4

4. Patch ordnet die Übergabe

Der Fix reiht zuerst verzögerte TX-Arbeit ein und signalisiert erst danach den Abschluss; so kann der Thread nicht vor der Planung fortfahren.

Quellcode: Verwundbar vs. Sicher

VERWUNDBARE IMPLEMENTIERUNG
// Relevante Reihenfolge in net/tls/tls_sw.c vor e01e3934a1b2
bool ready = false;

if (rec == first_rec)
    ready = true;

if (atomic_dec_and_test(&ctx->encrypt_pending))
    complete(&ctx->async_wait.completion);

if (!ready)
    return;

if (!test_and_set_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask))
    schedule_delayed_work(&ctx->tx_work.work, 1);
GEHÄRTETER SICHERHEITS-PATCH
// Relevante Reihenfolge in net/tls/tls_sw.c nach e01e3934a1b2
if (rec == first_rec) {
    // Stellen Sie die Sendeaufgabe ein, bevor Sie den übermittelnden Thread aufwecken.
    if (!test_and_set_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask))
        schedule_delayed_work(&ctx->tx_work.work, 1);
}

if (atomic_dec_and_test(&ctx->encrypt_pending))
    complete(&ctx->async_wait.completion);

Checkliste für Engineering & Systemsicherheit

Quellen