To the best of public knowledge, Januscape is the first guest-to-host KVM escape demonstrated on both Intel and AMD. This is not a coincidence of implementation — it is a direct consequence of where the bug lives.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/V4bel/Januscape/llms.txt
Use this file to discover all available pages before exploring further.
kvm_mmu_get_child_sp(), the function that performs the role-blind child shadow page reuse at [1], resides in arch/x86/kvm/mmu/mmu.c. That file is compiled once and shared by both the Intel VMX (kvm_intel.ko) and AMD SVM (kvm_amd.ko) paths. There is no per-vendor copy. Once nested virtualization is active, both architectures reach FNAME(fetch) → kvm_mmu_get_child_sp through the same ept_page_fault / npf_page_fault dispatch — the only difference is the page-table entry bit layout used to describe the nested page tables.
poc.c isolates that difference behind a single virt_ops struct, selected at module load time by the amd parameter.
The virt_ops Abstraction
build_world, the writer loop, the fault loop) calls only ops->huge_pte(), ops->tbl_pte(), and ops->leaf4k(), and is completely architecture-agnostic.
Page-Table Entry Bit Differences
EPT_RWX = 0x7), a memory type field (EPT_MT_WB = 6 << 3), and the page-size bit (EPT_PS = 1 << 7). AMD NPT entries use the standard x86 paging bits: Present (PF_P), Read/Write (PF_RW), User/Supervisor (PF_US), and Page Size (PF_PS = 0x80). The svm_tbl_pte and svm_leaf4k functions follow the same pattern, omitting PF_PS for non-leaf entries.
The backend is selected at module init:
Full Backend Structs
Intel (VMX/EPT):Intel vs AMD Execution Path
- Intel VMX/EPT
- AMD SVM/NPT
The Intel path calls
vmx_cpu_on() to execute vmxon with a per-CPU VMXON region, then vmx_vcpu_run() to set up a VMCS with EPT enabled (SEC_EPT in the secondary processor-based controls) and call vmlaunch. The EPT_POINTER VMCS field is set to the_root, which is nest_pml4_pa | 0x1e (walk length 4, memory type WB). L2 faults surface as EPT violations, dispatched by L0 through kvm_init_shadow_ept_mmu → ept_page_fault → ept_fetch → kvm_mmu_get_child_sp.Load command:Why Both Architectures Hit the Same Bug
When L1 runs a nested guest with EPT (Intel) or NPT (AMD), L0 must shadow L1’s nested page tables in software. For this, KVM initializes a non-directguest_mmu context:
guest_mmu’s root_role.direct is false at [16], is_tdp_mmu_active() returns false and the TDP MMU fast path is bypassed. The fault handler at [17] routes all nested faults into FNAME(fetch), which calls kvm_mmu_get_child_sp — the vulnerable function. The AMD counterpart kvm_init_shadow_npt_mmu sets up an identical non-direct guest_mmu. Neither path bypasses the shared shadow MMU code, which is exactly why the bug is architecture-neutral.
The nflood EPT-pointer flood optimization (
R_FLOOD role) is Intel-only because it exploits the VMCS EPT_POINTER field. On AMD the flood role is suppressed (cpu <= nflood && !amd), but the AMD path is still reliably exploitable with faulter threads alone.