]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: x86/mmu: pass pte_access for final nGPA->GPA walk
authorPaolo Bonzini <pbonzini@redhat.com>
Wed, 8 Apr 2026 15:42:01 +0000 (11:42 -0400)
committerPaolo Bonzini <pbonzini@redhat.com>
Sun, 10 May 2026 12:52:57 +0000 (14:52 +0200)
The XS/XU bit for EPT are only applied to final accesses, and use the
U bit from the page walk itself.  This is available in the page walker
as pte_access & ACC_USER_MASK but not available to translate_nested_gpa,
so pass it down.

Tested-by: David Riley <d.riley@proxmox.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/hyperv.c
arch/x86/kvm/mmu.h
arch/x86/kvm/mmu/mmu.c
arch/x86/kvm/mmu/paging_tmpl.h
arch/x86/kvm/mmu/spte.h
arch/x86/kvm/x86.c

index cf9dd565b8946b052060668ca8bf71f9c909e69e..53688f7b76eb9f7fc8dc29e10d6ad8ae87bfce27 100644 (file)
@@ -2042,7 +2042,7 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)
         */
        if (!hc->fast && is_guest_mode(vcpu)) {
                hc->ingpa = translate_nested_gpa(vcpu, hc->ingpa,
-                                       PFERR_GUEST_FINAL_MASK, NULL);
+                                       PFERR_GUEST_FINAL_MASK, NULL, 0);
                if (unlikely(hc->ingpa == INVALID_GPA))
                        return HV_STATUS_INVALID_HYPERCALL_INPUT;
        }
index 23f37535c0ce1d1e8e855ef3f94cae97cbb9c33c..635c2e5d8513dc0327f2d221007d21cf9235e860 100644 (file)
@@ -37,6 +37,12 @@ extern bool __read_mostly enable_mmio_caching;
 #define PT32_ROOT_LEVEL 2
 #define PT32E_ROOT_LEVEL 3
 
+#define ACC_READ_MASK    PT_PRESENT_MASK
+#define ACC_WRITE_MASK   PT_WRITABLE_MASK
+#define ACC_USER_MASK    PT_USER_MASK
+#define ACC_EXEC_MASK    8
+#define ACC_ALL          (ACC_EXEC_MASK | ACC_WRITE_MASK | ACC_USER_MASK | ACC_READ_MASK)
+
 #define KVM_MMU_CR4_ROLE_BITS (X86_CR4_PSE | X86_CR4_PAE | X86_CR4_LA57 | \
                               X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_PKE)
 
@@ -289,16 +295,19 @@ static inline void kvm_update_page_stats(struct kvm *kvm, int level, int count)
 }
 
 gpa_t translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u64 access,
-                          struct x86_exception *exception);
+                          struct x86_exception *exception,
+                          u64 pte_access);
 
 static inline gpa_t kvm_translate_gpa(struct kvm_vcpu *vcpu,
                                      struct kvm_mmu *mmu,
                                      gpa_t gpa, u64 access,
-                                     struct x86_exception *exception)
+                                     struct x86_exception *exception,
+                                     u64 pte_access)
 {
        if (mmu != &vcpu->arch.nested_mmu)
                return gpa;
-       return translate_nested_gpa(vcpu, gpa, access, exception);
+       return translate_nested_gpa(vcpu, gpa, access, exception,
+                                   pte_access);
 }
 
 static inline bool kvm_has_mirrored_tdp(const struct kvm *kvm)
index 6ac9f760d28cc3e02e8667bde2f6a802c1b05a3e..eb65f6c9c62137d00b2f5971ef4bca9254843fc3 100644 (file)
@@ -4348,8 +4348,14 @@ static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
 {
        if (exception)
                exception->error_code = 0;
+       /*
+        * EPT MBEC uses the effective access bits from the PTE to distinguish
+        * user and supervisor accesses, and treats every linear address as a
+        * user-mode address if CR0.PG=0.  Therefore *include* ACC_USER_MASK in
+        * the last argument to kvm_translate_gpa (which NPT does not use).
+        */
        return kvm_translate_gpa(vcpu, mmu, vaddr, access | PFERR_GUEST_FINAL_MASK,
-                                exception);
+                                exception, ACC_ALL);
 }
 
 static bool mmio_info_in_cache(struct kvm_vcpu *vcpu, u64 addr, bool direct)
index 567f8b77ffe05752d2e7bbac39a9d2b342d36b05..8dd9d510fc34d6eaa972b6641bc108afa3f154b7 100644 (file)
@@ -377,7 +377,7 @@ retry_walk:
 
                real_gpa = kvm_translate_gpa(vcpu, mmu, gfn_to_gpa(table_gfn),
                                             nested_access | PFERR_GUEST_PAGE_MASK,
-                                            &walker->fault);
+                                            &walker->fault, 0);
 
                /*
                 * FIXME: This can happen if emulation (for of an INS/OUTS
@@ -447,7 +447,7 @@ retry_walk:
 
        real_gpa = kvm_translate_gpa(vcpu, mmu, gfn_to_gpa(gfn),
                                     access | PFERR_GUEST_FINAL_MASK,
-                                    &walker->fault);
+                                    &walker->fault, walker->pte_access);
        if (real_gpa == INVALID_GPA)
                return 0;
 
index 121bfb2217e83d5c2926e2155cb9ded5ff5d3b00..8a4c09c5cdbfb3000670b92fe94047387f0ad3c2 100644 (file)
@@ -52,12 +52,6 @@ static_assert(SPTE_TDP_AD_ENABLED == 0);
 #define SPTE_BASE_ADDR_MASK (((1ULL << 52) - 1) & ~(u64)(PAGE_SIZE-1))
 #endif
 
-#define ACC_READ_MASK    PT_PRESENT_MASK
-#define ACC_WRITE_MASK   PT_WRITABLE_MASK
-#define ACC_USER_MASK    PT_USER_MASK
-#define ACC_EXEC_MASK    8
-#define ACC_ALL          (ACC_EXEC_MASK | ACC_WRITE_MASK | ACC_USER_MASK | ACC_READ_MASK)
-
 #define SPTE_LEVEL_BITS                        9
 #define SPTE_LEVEL_SHIFT(level)                __PT_LEVEL_SHIFT(level, SPTE_LEVEL_BITS)
 #define SPTE_INDEX(address, level)     __PT_INDEX(address, level, SPTE_LEVEL_BITS)
index ef1e3ae13887f62a82b65dcd05d047742a788f49..67979b7de5d6160b596f4126d4a578fcae9f2f78 100644 (file)
@@ -1073,7 +1073,7 @@ int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
         */
        real_gpa = kvm_translate_gpa(vcpu, mmu, gfn_to_gpa(pdpt_gfn),
                                     PFERR_USER_MASK | PFERR_WRITE_MASK |
-                                    PFERR_GUEST_PAGE_MASK, NULL);
+                                    PFERR_GUEST_PAGE_MASK, NULL, 0);
        if (real_gpa == INVALID_GPA)
                return 0;
 
@@ -7849,7 +7849,8 @@ void kvm_get_segment(struct kvm_vcpu *vcpu,
 }
 
 gpa_t translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u64 access,
-                          struct x86_exception *exception)
+                          struct x86_exception *exception,
+                          u64 pte_access)
 {
        struct kvm_mmu *mmu = vcpu->arch.mmu;
        gpa_t t_gpa;