vmm(4): wire faulted in pages
authormlarkin <mlarkin@openbsd.org>
Sat, 23 Jan 2021 22:34:46 +0000 (22:34 +0000)
committermlarkin <mlarkin@openbsd.org>
Sat, 23 Jan 2021 22:34:46 +0000 (22:34 +0000)
This change wires the pages used by virtual machines managed by vmm(4).
When uvm swaps out a page, vmm(4) does not properly do TLB flushing,
possibly leading to memory corruption or improper page access later.

While this diff is not the correct fix (implementing proper TLB flush
semantics), it does work around the problem by not letting the pages
get swapped out in the first place.

This means that under memory pressure, swap pages will have to come
from other processes, and it also means you cannot overcommit vmm(4)
memory assignment (eg, assign more memory to VMs than you actually
have).

It is my plan to fix this the correct way, but that will take time.

This issue was originally pointed out a long time ago by Maxime V., but
due to my taking a year away from OpenBSD, the issue remained unfixed.

sys/arch/amd64/amd64/vmm.c

index a406a6c..2f2fc66 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: vmm.c,v 1.274 2020/09/10 17:03:03 mpi Exp $   */
+/*     $OpenBSD: vmm.c,v 1.275 2021/01/23 22:34:46 mlarkin Exp $       */
 /*
  * Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org>
  *
@@ -988,7 +988,7 @@ vmx_mprotect_ept(vm_map_t vm_map, paddr_t sgpa, paddr_t egpa, int prot)
        for (addr = sgpa; addr < egpa; addr += PAGE_SIZE) {
                pte = vmx_pmap_find_pte_ept(pmap, addr);
                if (pte == NULL) {
-                       ret = uvm_fault(vm_map, addr, VM_FAULT_INVALID,
+                       ret = uvm_fault(vm_map, addr, VM_FAULT_WIRE,
                            PROT_READ | PROT_WRITE | PROT_EXEC);
                        if (ret)
                                printf("%s: uvm_fault returns %d, GPA=0x%llx\n",
@@ -5455,12 +5455,9 @@ svm_get_guest_faulttype(struct vmcb *vmcb)
 int
 svm_fault_page(struct vcpu *vcpu, paddr_t gpa)
 {
-       int fault_type, ret;
-       struct vmcb *vmcb = (struct vmcb *)vcpu->vc_control_va;
-
-       fault_type = svm_get_guest_faulttype(vmcb);
+       int ret;
 
-       ret = uvm_fault(vcpu->vc_parent->vm_map, gpa, fault_type,
+       ret = uvm_fault(vcpu->vc_parent->vm_map, gpa, VM_FAULT_WIRE,
            PROT_READ | PROT_WRITE | PROT_EXEC);
        if (ret)
                printf("%s: uvm_fault returns %d, GPA=0x%llx, rip=0x%llx\n",
@@ -5512,20 +5509,9 @@ svm_handle_np_fault(struct vcpu *vcpu)
 int
 vmx_fault_page(struct vcpu *vcpu, paddr_t gpa)
 {
-       int fault_type, ret;
-
-       fault_type = vmx_get_guest_faulttype();
-       if (fault_type == -1) {
-               printf("%s: invalid fault type\n", __func__);
-               return (EINVAL);
-       }
-
-       if (fault_type == VM_FAULT_PROTECT) {
-               vcpu->vc_exit.vee.vee_fault_type = VEE_FAULT_PROTECT;
-               return (EAGAIN);
-       }
+       int ret;
 
-       ret = uvm_fault(vcpu->vc_parent->vm_map, gpa, fault_type,
+       ret = uvm_fault(vcpu->vc_parent->vm_map, gpa, VM_FAULT_WIRE,
            PROT_READ | PROT_WRITE | PROT_EXEC);
 
        if (ret)