
CVE-2026-53359漏洞补丁
dump_tool.py automatically finds offsets; how to use it? Just read the code.
CVE-2026-53359 (Januscape) is a use-after-free (UAF) vulnerability in the Linux kernel KVM shadow MMU.
The kvm_mmu_get_page() function, when searching the hash table for a reusable shadow page table, only compares the gfn (guest physical frame number) and does not compare the role (page table role / MMU role), causing page tables with mismatched roles to be incorrectly reused, leading to UAF.
Before fix (vulnerable):
┌──────────────────────────────────────┐
│ kvm_mmu_get_page() │
│ Traverse hash table │
│ if (child->gfn == gfn) │
│ return child ← compares only gfn! │
│ Role mismatch leads to reuse → UAF!│
│ Allocate new page (safe) │
└──────────────────────────────────────┘
In the upstream kernel commit 81ccda30b4e8, a line comparing role was added:
// Before fix
if (... && spte_to_child_sp(*sptep)->gfn == gfn)
// After fix
if (... && spte_to_child_sp(*sptep)->gfn == gfn
&& spte_to_child_sp(*sptep)->role.word == role.word)
No kernel source modification, no function replacement; directly modifies the vulnerable instruction in the running kernel memory.
Binary level:
Offset 0x104: 49 39 47 28 cmp %rax, 0x28(%r15) ← compare gfn
Offset 0x108: 0f 84 9f 01 00 00 je +0x19f ← if match, jump to reuse
After patching:
Offset 0x108: 66 0f 1f 44 00 00 NOP × 6 ← do nothing
After fix:
┌──────────────────────────────────────┐
│ kvm_mmu_get_page() │
│ Traverse hash table │
│ if (child->gfn == gfn) │
│ NOP (jump erased, slides through)│
│ Allocate new page (forced safe path)│
│ → No reuse = No UAF = Vulnerability fixed│
└──────────────────────────────────────┘
kvm_mmu_get_page via kallsyms_lookup_nametext_poke (kernel code hot-patch API) via kallsyms_lookup_namestop_machine to pause all CPUs, ensuring safe modificationtext_poke to replace the 6-byte je instruction with a 6-byte NOPtext_poke| Method | Issue |
|---|---|
| Upgrade kernel and reboot | Requires host reboot, all VMs down |
| nested=0 (disable nested virtualization) | Loss of nested virtualization functionality, cannot run VMs inside VMs |
| kpatch method | Requires kernel-debuginfo, compilation takes 10-20 minutes, complex dependencies |
| ftrace function replacement | kvm_mmu_get_child_sp is inlined by GCC, no independent function entry |
| My text_poke method | Compilation in 10 seconds, one .c file, directly modifies the vulnerable instruction |
| Feature | Impact |
|---|---|
| Host reboot | Not required |
| VM reboot/migration | Not required |
| Nested virtualization (VM inside VM) | Preserved, normal operation |
| Create/start VMs | Normal |
| KSM memory merging | Unaffected, independent feature |
| CPU performance | Nearly no impact (NOP does not consume CPU) |
| Memory | Shadow page tables no longer reused; each allocation gets a new page, slightly more memory usage |
| KVM module unload | Normal (rmmod automatically restores original code) |
| Condition | Description |
|---|---|
| Kernel version | Linux 4.18+ (CentOS 8 / RHEL 8 / Rocky 8 etc.) |
| Build environment | kernel-devel + gcc + make |
| Host reboot | Not needed |
| VM shutdown | Not needed |
| Nested virtualization | Preserved |
# Compile
make
# Load hot patch
insmod KVM-XJ.ko
# Check status
dmesg | grep KVM-XJ
cat /sys/module/kvm_intel/parameters/nested # should still be 1
lsmod | grep KVM_XJ
# Unload (restore original code)
rmmod KVM_XJ
Different kernel versions have different compilation optimizations; the offset of the je instruction also varies. Use dump_tool.py for automatic analysis:
# 1. Download kvm.ko from the host
scp root@host:/lib/modules/.../kvm.ko.xz .
xz -d kvm.ko.xz
# 2. Run the analysis tool
python dump_tool.py kvm.ko
# 3. The tool will output the patch offset; modify 0x108 in KVM-XJ.c accordingly
| Kernel Version | je Offset | Status |
|---|---|---|
| 4.18.0-496.el8.x86_64 | 0x108 | Tested |
| 4.18.0-358.el8.x86_64 | 0xe8 | Tested |