KVM's behavior when the guest writes to a non-writable VMA is inconsistent.
For regular, page-backed mappings it returns KVM_PFN_ERR_FAULT and thus
returns -EFAULT to userspace (which is ABI, and relied upon by tests);
for VM_IO/VM_PFNMAP mappings instead it returns KVM_PFN_ERR_RO_FAULT
and thus exits to userspace with KVM_EXIT_MMIO.

This behavior for VM_{IO,PFNMAP} was added by commit bd2fae8da794 ("KVM:
do not assume PTE is writable after follow_pfn"), and even if it has been
in place for five years it is unlikely that it is relied upon by userspace,
since it is inconsistent with KVM itself.  Change hva_to_pfn() to return
KVM_PFN_ERR_FAULT for all non-writable VMAs, and restrict KVM_EXIT_MMIO
to the case of an explicitly read-only memslot.

Suggested-by: Sean Christopherson <[email protected]>
Signed-off-by: Paolo Bonzini <[email protected]>
---
 virt/kvm/kvm_main.c | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index b7c21a48a45c..da5b0bb62590 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -2999,15 +2999,10 @@ kvm_pfn_t hva_to_pfn(struct kvm_follow_pfn *kfp)
         * or the page might be absent.
         */
 
-       if (vma == NULL || unlikely(!(vma->vm_flags & VM_READ))) {
+       if (vma == NULL ||
+           unlikely(!(vma->vm_flags & VM_READ)) ||
+           ((kfp->flags & FOLL_WRITE) && unlikely(!(vma->vm_flags & 
VM_WRITE)))) {
                pfn = KVM_PFN_ERR_FAULT;
-       } else if ((kfp->flags & FOLL_WRITE) && unlikely(!(vma->vm_flags & 
VM_WRITE))) {
-               /*
-                * Exit to userspace for PROT_READ mappings in a writable
-                * memslot, as this is part of the API.
-                */
-               pfn = vma->vm_flags & (VM_IO | VM_PFNMAP) ? 
KVM_PFN_ERR_RO_FAULT :
-                       KVM_PFN_ERR_FAULT;
        } else if (vma->vm_flags & (VM_IO | VM_PFNMAP)) {
                r = hva_to_pfn_remapped(vma, kfp, &pfn);
                if (r == -EAGAIN)
-- 
2.55.0

Reply via email to