From: David Woodhouse <[email protected]>

KVM_TRANSLATE hardcodes writeable = 1, so userspace answering
HvCallTranslateVirtualAddress from this ioctl cannot honour the
hypercall's write-validation flag: validating write access against a
read-only PTE succeeds instead of reporting the address unmapped, and
the Windows secure kernel's page verification trusts a mapping it
cannot write.

Walk the address a second time with PFERR_WRITE_MASK at supervisor
level and report the outcome, matching the reference hypervisor's
validation walk.

Signed-off-by: David Woodhouse <[email protected]>
Assisted-by: LLM
---
 arch/x86/kvm/x86.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index afd668c6db3f..491a0360c403 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -13305,10 +13305,19 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu 
*vcpu,
 
        idx = srcu_read_lock(&vcpu->kvm->srcu);
        gpa = kvm_mmu_gva_to_gpa_system(vcpu, vaddr, NULL);
+       /*
+        * Report write access from a supervisor-level walk instead of the
+        * hardcoded 1: Hyper-V's TranslateVirtualAddress write validation
+        * is answered from this ioctl, and the reference hypervisor walks
+        * with PFERR_WRITE_MASK and no user bit.
+        */
+       tr->writeable = vcpu->arch.walk_mmu->gva_to_gpa(vcpu,
+                                                       vcpu->arch.walk_mmu,
+                                                       vaddr, PFERR_WRITE_MASK,
+                                                       NULL) != INVALID_GPA;
        srcu_read_unlock(&vcpu->kvm->srcu, idx);
        tr->physical_address = gpa;
        tr->valid = gpa != INVALID_GPA;
-       tr->writeable = 1;
        tr->usermode = 0;
 
        vcpu_put(vcpu);
-- 
2.50.1


Reply via email to