From: Mickaël Salaün <mic@xxxxxxxxxxx> Add EPT_VIOLATION_PROT_USER_EXEC (6) to reflect the user executable permissions of a given address when Intel MBEC is enabled. Refactor usage of EPT_VIOLATION_RWX_TO_PROT to understand all of the specific bits that are now possible with MBEC. Intel SDM 'Exit Qualification for EPT Violations' states the following for Bit 6. If the “mode-based execute control” VM-execution control is 0, the value of this bit is undefined. If that control is 1, this bit is the logical-AND of bit 10 in the EPT paging-structure entries used to translate the guest-physical address of the access causing the EPT violation. In this case, it indicates whether the guest-physical address was executable for user-mode linear addresses. Bit 6 is cleared to 0 if (1) the “mode-based execute control” VM-execution control is 1; and (2) either (a) any of EPT paging-structure entries used to translate the guest-physical address of the access causing the EPT violation is not present; or (b) 4-level EPT is in use and the guest-physical address sets any bits in the range 51:48. Signed-off-by: Mickaël Salaün <mic@xxxxxxxxxxx> Co-developed-by: Jon Kohler <jon@xxxxxxxxxxx> Signed-off-by: Jon Kohler <jon@xxxxxxxxxxx> --- arch/x86/include/asm/vmx.h | 7 ++++--- arch/x86/kvm/mmu/paging_tmpl.h | 15 ++++++++++++--- arch/x86/kvm/vmx/vmx.c | 7 +++++-- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index ffc90d672b5d..84c5be416f5c 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -587,6 +587,7 @@ enum vm_entry_failure_code { #define EPT_VIOLATION_PROT_READ BIT(3) #define EPT_VIOLATION_PROT_WRITE BIT(4) #define EPT_VIOLATION_PROT_EXEC BIT(5) +#define EPT_VIOLATION_PROT_USER_EXEC BIT(6) #define EPT_VIOLATION_PROT_MASK (EPT_VIOLATION_PROT_READ | \ EPT_VIOLATION_PROT_WRITE | \ EPT_VIOLATION_PROT_EXEC) @@ -596,7 +597,7 @@ enum vm_entry_failure_code { #define EPT_VIOLATION_READ_TO_PROT(__epte) (((__epte) & VMX_EPT_READABLE_MASK) << 3) #define EPT_VIOLATION_WRITE_TO_PROT(__epte) (((__epte) & VMX_EPT_WRITABLE_MASK) << 3) #define EPT_VIOLATION_EXEC_TO_PROT(__epte) (((__epte) & VMX_EPT_EXECUTABLE_MASK) << 3) -#define EPT_VIOLATION_RWX_TO_PROT(__epte) (((__epte) & VMX_EPT_RWX_MASK) << 3) +#define EPT_VIOLATION_USER_EXEC_TO_PROT(__epte) (((__epte) & VMX_EPT_USER_EXECUTABLE_MASK) >> 4) static_assert(EPT_VIOLATION_READ_TO_PROT(VMX_EPT_READABLE_MASK) == (EPT_VIOLATION_PROT_READ)); @@ -604,8 +605,8 @@ static_assert(EPT_VIOLATION_WRITE_TO_PROT(VMX_EPT_WRITABLE_MASK) == (EPT_VIOLATION_PROT_WRITE)); static_assert(EPT_VIOLATION_EXEC_TO_PROT(VMX_EPT_EXECUTABLE_MASK) == (EPT_VIOLATION_PROT_EXEC)); -static_assert(EPT_VIOLATION_RWX_TO_PROT(VMX_EPT_RWX_MASK) == - (EPT_VIOLATION_PROT_READ | EPT_VIOLATION_PROT_WRITE | EPT_VIOLATION_PROT_EXEC)); +static_assert(EPT_VIOLATION_USER_EXEC_TO_PROT(VMX_EPT_USER_EXECUTABLE_MASK) == + (EPT_VIOLATION_PROT_USER_EXEC)); /* * Exit Qualifications for NOTIFY VM EXIT diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index 9bc3fc4a238b..a3a5cacda614 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -181,8 +181,9 @@ static inline unsigned FNAME(gpte_access)(u64 gpte) unsigned access; #if PTTYPE == PTTYPE_EPT access = ((gpte & VMX_EPT_WRITABLE_MASK) ? ACC_WRITE_MASK : 0) | - ((gpte & VMX_EPT_EXECUTABLE_MASK) ? ACC_EXEC_MASK : 0) | - ((gpte & VMX_EPT_READABLE_MASK) ? ACC_USER_MASK : 0); + ((gpte & VMX_EPT_EXECUTABLE_MASK) ? ACC_EXEC_MASK : 0) | + ((gpte & VMX_EPT_USER_EXECUTABLE_MASK) ? ACC_USER_EXEC_MASK : 0) | + ((gpte & VMX_EPT_READABLE_MASK) ? ACC_USER_MASK : 0); #else BUILD_BUG_ON(ACC_EXEC_MASK != PT_PRESENT_MASK); BUILD_BUG_ON(ACC_EXEC_MASK != 1); @@ -510,7 +511,15 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, * Note, pte_access holds the raw RWX bits from the EPTE, not * ACC_*_MASK flags! */ - walker->fault.exit_qualification |= EPT_VIOLATION_RWX_TO_PROT(pte_access); + walker->fault.exit_qualification |= + EPT_VIOLATION_READ_TO_PROT(pte_access); + walker->fault.exit_qualification |= + EPT_VIOLATION_WRITE_TO_PROT(pte_access); + walker->fault.exit_qualification |= + EPT_VIOLATION_EXEC_TO_PROT(pte_access); + if (vcpu->arch.pt_guest_exec_control) + walker->fault.exit_qualification |= + EPT_VIOLATION_USER_EXEC_TO_PROT(pte_access); } #endif walker->fault.address = addr; diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 116910159a3f..0aadfa924045 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -5809,7 +5809,7 @@ static int handle_task_switch(struct kvm_vcpu *vcpu) static int handle_ept_violation(struct kvm_vcpu *vcpu) { - unsigned long exit_qualification; + unsigned long exit_qualification, rwx_mask; gpa_t gpa; u64 error_code; @@ -5839,7 +5839,10 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu) error_code |= (exit_qualification & EPT_VIOLATION_ACC_INSTR) ? PFERR_FETCH_MASK : 0; /* ept page table entry is present? */ - error_code |= (exit_qualification & EPT_VIOLATION_PROT_MASK) + rwx_mask = EPT_VIOLATION_PROT_MASK; + if (vcpu->arch.pt_guest_exec_control) + rwx_mask |= EPT_VIOLATION_PROT_USER_EXEC; + error_code |= (exit_qualification & rwx_mask) ? PFERR_PRESENT_MASK : 0; if (error_code & EPT_VIOLATION_GVA_IS_VALID) -- 2.43.0