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

