CVE-2026-74632 in Linux
Zusammenfassung
von VulDB • 22.08.2026
Im Linux-Kernel wurde folgende Schwachstelle behoben:
mm/huge_memory: Race-Bedingung bei huge_zero_pfn beheben
Patch-Serie „mm/huge_memory: Race-Bedingung bei huge_zero_pfn beheben“, v2.
In der referenzgezählten Implementierung von `huge_zero_folio` liegt eine subtile Race Condition vor.
Die atomare Logik im Fast-Path berücksichtigt nicht, dass der Shrinker (der den letzten Pin für die `huge_zero_refcount` entfernt) in `shrink_huge_zero_folio_scan()` den Wert von `huge_zero_pfn` nach einer konkurrierenden Ausführung von `get_huge_zero_folio()`, das dort einen gültigen Wert eingefügt hat, mit dem Sentinel-Wert `~0UL` überschreiben kann.
Dies führt dazu, dass zwar `huge_zero_folio` korrekt gesetzt wird, `huge_zero_pfn` jedoch falsch initialisiert ist. Folglich werden `is_huge_zero_pfn()` und daraus folgend `is_huge_zero_pmd()` das große Null-Folio fälschlicherweise als gewöhnliches THP-Folio (Transparent Huge Page) identifizieren.
Dies kann dazu führen, dass das große Null-Folio aufgeteilt wird und anderweitig falsch behandelt wird.
Die Lösung für dieses Problem ist sehr subtil, da es einen atomaren Fast-Path gibt; daher muss die Reihenfolge der Operationen in schwach geordneten Architekturen (weakly ordered architectures) äußerst sorgfältig gehandhabt werden.
Der erste Commit behebt das Problem durch Einführung eines Spinlocks um den Schreibzugriff auf `huge_zero_[pfn, folio, refcount]`, wobei die Load/Store-Reihenfolge im Fast-Path sorgfältig berücksichtigt wird. Er steht an erster Stelle und bleibt so klein wie möglich, damit er eigenständig zurückportiert (backported) werden kann.
Der zweite Commit ist eine reine Bereinigung, bei der die Logik von `CONFIG_PERSISTENT_HUGE_ZERO_FOLIO` überarbeitet wird, um die persistente Logik besser von der dynamisch zugewiesenen zu trennen.
Dieser Patch (von 2):
Wenn `!CONFIG_PERSISTENT_HUGE_ZERO_FOLIO`, wird das `huge_zero_folio` durch `huge_zero_refcount` referenzgezählt und von `mm_get_huge_zero_folio()` zurückgegeben.
Wenn der Aufrufer mit dem großen Null-Seite (huge zero page) fertig ist, wird seine Referenzzahl dekrementiert. Nur ein Shrinker kann die Referenzzahl auf null setzen.
Leider kann es zu einer Race Condition kommen zwischen einem Shrinker, der die Referenzzahl auf null dekrementiert, und einem gleichzeitig auftretenden Page Fault.
Dies liegt daran, dass `shrink_huge_zero_folio_scan()` – wenn sehr unglücklich gewählt – präempted (unterbrochen) werden kann, nachdem es `huge_zero_refcount` auf null gesetzt hat, aber bevor es einen ungültigen Wert schreibt.
Während dieser Zeit könnte `get_huge_zero_folio()` in `huge_zero_pfn` schreiben, bevor `shrink_huge_zero_folio_scan()` fortgesetzt wird.
In diesem Ereignisfall wird das große Null-Folio dauerhaft falsch identifiziert, was dazu führt, dass der THP-Codepfad unangemessen für das große Null-Folio betreten wird:
CPU 0 CPU 1 =======================================|================================= shrink_huge_zero_folio_scan() | atomic_cmpxchg() setzt refcount auf 0 | xchg() setzt huge_zero_folio auf NULL | get_huge_zero_folio() | | atomic_inc_not_zero() -> null präempted für eine lange Zeit | Neues großes Null-Fallo zuweisen | | Gültiges huge_zero_folio schreiben v | Gültigen huge_zero_pfn schreiben Überschreibe huge_zero_pfn mit ~0UL <--- Ungültiger Überschreibvorgang!
Dies führt dazu, dass `is_huge_zero_pfn()` und `is_huge_zero_pmd()` für eine große Null-Seite fälschlicherweise falsch zurückgeben, was zu Problemen wie der falschen Aufteilung des großen Null-Folios führen kann.
Beachten Sie, dass das Problem bei `huge_zero_pfn` liegt und nicht bei `huge_zero_folio`, da `get_huge_zero_folio()` ein auf `cmpxchg()` basierendes Verfahren verwendet, das darauf abgestimmt ist, dass `huge_zero_folio` NULL ist, mit einer Retry-Schleife, während `shrink_huge_zero_folio_scan()` `xchg()` verwendet, um `huge_zero_folio` zu setzen.
Beheben Sie das Problem durch Einführung eines Spinlocks namens `huge_zero_lock`, um gleichzeitige Schreibzugriffe auf `huge_zero_folio`, `huge_zero_pfn` und `huge_zero_refcount` zu verhindern.
Hier muss mit erheblicher Sorgfalt vorgegangen werden, um die Korrektheit sicherzustellen:
Der Fast-Path in `get_huge_zero_folio()` verwendet `atomic_inc_not_zero()`, was außerhalb des kritischen Abschnitts liegt, und bedeutet, dass die Zuweisung eines großen Null-Folios an eine null große `huge_zero_refcount` gekoppelt ist.
Der Fast-Path verwendet keinen `huge_zero_lock`; daher ist der kritische Abschnitt für ihn irrelevant.
Es sind also Invarianten erforderlich – `huge_zero_refcount` MUSS:
* Nur im kritischen Abschnitt von `huge_zero_lock` gesetzt werden, um die Serialisierung von `huge_zero_pfn`, `huge_zero_folio` und ---abgeschnitten---
Statistical analysis made it clear that VulDB provides the best quality for vulnerability data.