struct nested_vmx {
        /* Has the level1 guest done vmxon? */
        bool vmxon;
+       gpa_t vmxon_ptr;
 
        /* The guest-physical address of the current VMCS L1 keeps for L2 */
        gpa_t current_vmptr;
        return 0;
 }
 
+/*
+ * This function performs the various checks including
+ * - if it's 4KB aligned
+ * - No bits beyond the physical address width are set
+ * - Returns 0 on success or else 1
+ */
+static int nested_vmx_check_vmptr(struct kvm_vcpu *vcpu, int exit_reason)
+{
+       gva_t gva;
+       gpa_t vmptr;
+       struct x86_exception e;
+       struct page *page;
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       int maxphyaddr = cpuid_maxphyaddr(vcpu);
+
+       if (get_vmx_mem_address(vcpu, vmcs_readl(EXIT_QUALIFICATION),
+                       vmcs_read32(VMX_INSTRUCTION_INFO), &gva))
+               return 1;
+
+       if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, &vmptr,
+                               sizeof(vmptr), &e)) {
+               kvm_inject_page_fault(vcpu, &e);
+               return 1;
+       }
+
+       switch (exit_reason) {
+       case EXIT_REASON_VMON:
+               /*
+                * SDM 3: 24.11.5
+                * The first 4 bytes of VMXON region contain the supported
+                * VMCS revision identifier
+                *
+                * Note - IA32_VMX_BASIC[48] will never be 1
+                * for the nested case;
+                * which replaces physical address width with 32
+                *
+                */
+               if (!IS_ALIGNED(vmptr, PAGE_SIZE) || (vmptr >> maxphyaddr)) {
+                       nested_vmx_failInvalid(vcpu);
+                       skip_emulated_instruction(vcpu);
+                       return 1;
+               }
+
+               page = nested_get_page(vcpu, vmptr);
+               if (page == NULL ||
+                   *(u32 *)kmap(page) != VMCS12_REVISION) {
+                       nested_vmx_failInvalid(vcpu);
+                       kunmap(page);
+                       skip_emulated_instruction(vcpu);
+                       return 1;
+               }
+               kunmap(page);
+               vmx->nested.vmxon_ptr = vmptr;
+               break;
+
+       default:
+               return 1; /* shouldn't happen */
+       }
+
+       return 0;
+}
+
 /*
  * Emulate the VMXON instruction.
  * Currently, we just remember that VMX is active, and do not save or even
                kvm_inject_gp(vcpu, 0);
                return 1;
        }
+
+       if (nested_vmx_check_vmptr(vcpu, EXIT_REASON_VMON))
+               return 1;
+
        if (vmx->nested.vmxon) {
                nested_vmx_failValid(vcpu, VMXERR_VMXON_IN_VMX_ROOT_OPERATION);
                skip_emulated_instruction(vcpu);