Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: TDX: Detect unexpected SEPT violations due to pending SPTEs

Detect SEPT violations that occur when an SEPT entry is in PENDING state
while the TD is configured not to receive #VE on SEPT violations.

A TD guest can be configured not to receive #VE by setting SEPT_VE_DISABLE
to 1 in tdh_mng_init() or modifying pending_ve_disable to 1 in TDCS when
flexible_pending_ve is permitted. In such cases, the TDX module will not
inject #VE into the TD upon encountering an EPT violation caused by an SEPT
entry in the PENDING state. Instead, TDX module will exit to VMM and set
extended exit qualification type to PENDING_EPT_VIOLATION and exit
qualification bit 6:3 to 0.

Since #VE will not be injected to such TDs, they are not able to be
notified to accept a GPA. TD accessing before accepting a private GPA
is regarded as an error within the guest.

Detect such guest error by inspecting the (extended) exit qualification
bits and make such VM dead.

Cc: Xiaoyao Li <xiaoyao.li@intel.com>
Cc: Rick Edgecombe <rick.p.edgecombe@intel.com>
Signed-off-by: Yan Zhao <yan.y.zhao@intel.com>
Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
Message-ID: <20250227012021.1778144-3-binbin.wu@linux.intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Yan Zhao and committed by
Paolo Bonzini
e6a85781 da407fe4

+21
+2
arch/x86/include/asm/vmx.h
··· 585 585 #define EPT_VIOLATION_ACC_WRITE_BIT 1 586 586 #define EPT_VIOLATION_ACC_INSTR_BIT 2 587 587 #define EPT_VIOLATION_RWX_SHIFT 3 588 + #define EPT_VIOLATION_EXEC_R3_LIN_BIT 6 588 589 #define EPT_VIOLATION_GVA_IS_VALID_BIT 7 589 590 #define EPT_VIOLATION_GVA_TRANSLATED_BIT 8 590 591 #define EPT_VIOLATION_ACC_READ (1 << EPT_VIOLATION_ACC_READ_BIT) 591 592 #define EPT_VIOLATION_ACC_WRITE (1 << EPT_VIOLATION_ACC_WRITE_BIT) 592 593 #define EPT_VIOLATION_ACC_INSTR (1 << EPT_VIOLATION_ACC_INSTR_BIT) 593 594 #define EPT_VIOLATION_RWX_MASK (VMX_EPT_RWX_MASK << EPT_VIOLATION_RWX_SHIFT) 595 + #define EPT_VIOLATION_EXEC_FOR_RING3_LIN (1 << EPT_VIOLATION_EXEC_R3_LIN_BIT) 594 596 #define EPT_VIOLATION_GVA_IS_VALID (1 << EPT_VIOLATION_GVA_IS_VALID_BIT) 595 597 #define EPT_VIOLATION_GVA_TRANSLATED (1 << EPT_VIOLATION_GVA_TRANSLATED_BIT) 596 598
+17
arch/x86/kvm/vmx/tdx.c
··· 1709 1709 trace_kvm_apicv_accept_irq(vcpu->vcpu_id, delivery_mode, trig_mode, vector); 1710 1710 } 1711 1711 1712 + static inline bool tdx_is_sept_violation_unexpected_pending(struct kvm_vcpu *vcpu) 1713 + { 1714 + u64 eeq_type = to_tdx(vcpu)->ext_exit_qualification & TDX_EXT_EXIT_QUAL_TYPE_MASK; 1715 + u64 eq = vmx_get_exit_qual(vcpu); 1716 + 1717 + if (eeq_type != TDX_EXT_EXIT_QUAL_TYPE_PENDING_EPT_VIOLATION) 1718 + return false; 1719 + 1720 + return !(eq & EPT_VIOLATION_RWX_MASK) && !(eq & EPT_VIOLATION_EXEC_FOR_RING3_LIN); 1721 + } 1722 + 1712 1723 static int tdx_handle_ept_violation(struct kvm_vcpu *vcpu) 1713 1724 { 1714 1725 unsigned long exit_qual; 1715 1726 gpa_t gpa = to_tdx(vcpu)->exit_gpa; 1716 1727 1717 1728 if (vt_is_tdx_private_gpa(vcpu->kvm, gpa)) { 1729 + if (tdx_is_sept_violation_unexpected_pending(vcpu)) { 1730 + pr_warn("Guest access before accepting 0x%llx on vCPU %d\n", 1731 + gpa, vcpu->vcpu_id); 1732 + kvm_vm_dead(vcpu->kvm); 1733 + return -EIO; 1734 + } 1718 1735 /* 1719 1736 * Always treat SEPT violations as write faults. Ignore the 1720 1737 * EXIT_QUALIFICATION reported by TDX-SEAM for SEPT violations.
+2
arch/x86/kvm/vmx/tdx_arch.h
··· 70 70 #define TDX_TD_ATTR_KL BIT_ULL(31) 71 71 #define TDX_TD_ATTR_PERFMON BIT_ULL(63) 72 72 73 + #define TDX_EXT_EXIT_QUAL_TYPE_MASK GENMASK(3, 0) 74 + #define TDX_EXT_EXIT_QUAL_TYPE_PENDING_EPT_VIOLATION 6 73 75 /* 74 76 * TD_PARAMS is provided as an input to TDH_MNG_INIT, the size of which is 1024B. 75 77 */