
CVE-2026-53359漏洞补丁
dump_tool.py sucht automatisch Offsets. Wie man es verwendet, steht im Code.
CVE-2026-53359 (Januscape) ist eine Use-After-Free (UAF) Schwachstelle im KVM Shadow MMU des Linux-Kernels.
Die Funktion kvm_mmu_get_page() vergleicht bei der Suche nach wiederverwendbaren Schattenseitentabellen in der Hashtabelle nur die gfn (Gast-Physikalische-Seitenrahmennummer), aber nicht die role (Seitentabellen-Rolle/MMU-Rolle), was dazu führt, dass Seitentabellen mit nicht übereinstimmenden Rollen fälschlicherweise wiederverwendet werden, was einen UAF auslöst.
Vor dem Patch (anfällig):
┌──────────────────────────────────────┐
│ kvm_mmu_get_page() │
│ Hashtabelle durchlaufen │
│ if (child->gfn == gfn) │
│ return child ← nur gfn verglichen!│
│ Wiederverwendung auch bei │
│ Rollenkonflikt → UAF! │
│ Neue Seite zuweisen (sicher) │
└──────────────────────────────────────┘
Im Upstream-Kernel-Commit 81ccda30b4e8 wurde eine Zeile zum Rollenvergleich hinzugefügt:
// Vor dem Patch
if (... && spte_to_child_sp(*sptep)->gfn == gfn)
// Nach dem Patch
if (... && spte_to_child_sp(*sptep)->gfn == gfn
&& spte_to_child_sp(*sptep)->role.word == role.word)
Es wird weder der Kernel-Quellcode geändert noch eine Funktion ersetzt, sondern direkt die anfällige Anweisung im laufenden Kernel-Speicher modifiziert.
Auf Binärebene:
Offset 0x104: 49 39 47 28 cmp %rax, 0x28(%r15) ← vergleicht gfn
Offset 0x108: 0f 84 9f 01 00 00 je +0x19f ← bei Treffer springen und wiederverwenden
Nach dem Patch:
Offset 0x108: 66 0f 1f 44 00 00 NOP × 6 ← tut nichts
Nach dem Patch:
┌──────────────────────────────────────┐
│ kvm_mmu_get_page() │
│ Hashtabelle durchlaufen │
│ if (child->gfn == gfn) │
│ NOP (Sprung gelöscht, gleitet vorbei)│
│ Neue Seite zuweisen (erzwingt │
│ sicheren Pfad) │
│ → Keine Wiederverwendung = │
│ kein UAF = Schwachstelle behoben │
└──────────────────────────────────────┘
kvm_mmu_get_page über kallsyms_lookup_name findentext_poke Funktion über kallsyms_lookup_name finden (Kernel-Code-Hotpatch-API)stop_machine anhalten, um sichere Änderung zu gewährleistentext_poke die 6-Byte je-Anweisung durch 6-Byte NOP ersetzentext_poke wiederherstellen| Lösung | Problem |
|---|---|
| Kernel-Upgrade mit Neustart | Erfordert Host-Neustart, alle VMs werden gestoppt |
| nested=0 (Verschachtelte Virtualisierung deaktivieren) | Verlust der verschachtelten Virtualisierung, keine Ausführung von VMs in VMs möglich |
| kpatch-Methode | Benötigt kernel-debuginfo, Kompilierung dauert 10-20 Minuten, komplexe Abhängigkeiten |
| ftrace Funktionsersetzung | kvm_mmu_get_child_sp wird von GCC inline gesetzt, keine eigenständige Funktionseinsprungstelle |
| Meine text_poke-Lösung | Kompilierung in 10 Sekunden, eine .c-Datei, direkte Modifikation der anfälligen Anweisung |
| Funktion | Auswirkung |
|---|---|
| Host-Neustart | Nicht erforderlich |
| VM-Neustart/-Migration | Nicht erforderlich |
| Verschachtelte Virtualisierung (VM in VM) | Beibehalten, normale Nutzung |
| Erstellen/Starten von VMs | Normal |
| KSM-Speicherzusammenführung | Keine Auswirkung, unabhängige Funktion |
| CPU-Leistung | Nahezu keine Auswirkung (NOP verbraucht keine CPU) |
| Speicher | Schattenseitentabellen werden nicht mehr wiederverwendet, jede Seite neu zugewiesen, geringer Speichermehrverbrauch |
| KVM-Modul entladen | Normal (rmmod stellt ursprünglichen Code automatisch wieder her) |
| Bedingung | Beschreibung |
|---|---|
| Kernel-Version | Linux 4.18+ (CentOS 8 / RHEL 8 / Rocky 8 usw.) |
| Build-Umgebung | kernel-devel + gcc + make |
| Host-Neustart | Nicht erforderlich |
| VM-Stopp | Nicht erforderlich |
| Verschachtelte Virtualisierung | Beibehalten |
# Kompilieren
make
# Hotpatch laden
insmod KVM-XJ.ko
# Status anzeigen
dmesg | grep KVM-XJ
cat /sys/module/kvm_intel/parameters/nested # sollte immer noch 1 sein
lsmod | grep KVM_XJ
# Entladen (ursprünglichen Code wiederherstellen)
rmmod KVM_XJ
Unterschiedliche Kernelversionen haben unterschiedliche Compileroptimierungen, daher variiert der Offset der je-Anweisung. Verwenden Sie dump_tool.py zur automatischen Analyse:
# 1. kvm.ko vom Host herunterladen
scp root@Host:/lib/modules/.../kvm.ko.xz .
xz -d kvm.ko.xz
# 2. Analysetool ausführen
python dump_tool.py kvm.ko
# 3. Das Tool gibt den Patch-Offset aus; ändern Sie 0x108 in KVM-XJ.c
| Kernel-Version | je-Offset | Status |
|---|---|---|
| 4.18.0-496.el8.x86_64 | 0x108 | Getestet |
| 4.18.0-358.el8.x86_64 | 0xe8 | Getestet |