vmm(4): add limit to number of vcpus
authordv <dv@openbsd.org>
Mon, 13 Sep 2021 22:16:27 +0000 (22:16 +0000)
committerdv <dv@openbsd.org>
Mon, 13 Sep 2021 22:16:27 +0000 (22:16 +0000)
After fixing previous syzbot issues related to lock contention, the reproducer code managed to hit an issue where it can exhaust kernel memory by allocating vcpus. Since each vcpu (regardless if it's SVM or VMX-capable) requires wiring some number of pages of memory, it was possible to starve other parts of the kernel.

This change limits the total number of vcpus to 512, a conservative number given vmm(4) only supports single vcpu guests at the moment.

ok mlarkin@

sys/arch/amd64/amd64/vmm.c
sys/arch/amd64/include/vmmvar.h

index 1ee57d1..3ddd41a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: vmm.c,v 1.292 2021/09/05 16:36:34 dv Exp $    */
+/*     $OpenBSD: vmm.c,v 1.293 2021/09/13 22:16:27 dv Exp $    */
 /*
  * Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org>
  *
@@ -99,6 +99,9 @@ struct vmm_softc {
 
        int                     mode;
 
+       size_t                  vcpu_ct;
+       size_t                  vcpu_max;
+
        struct rwlock           vm_lock;
        size_t                  vm_ct;          /* number of in-memory VMs */
        size_t                  vm_idx;         /* next unique VM index */
@@ -368,6 +371,7 @@ vmm_attach(struct device *parent, struct device *self, void *aux)
        sc->nr_svm_cpus = 0;
        sc->nr_rvi_cpus = 0;
        sc->nr_ept_cpus = 0;
+       sc->vcpu_ct = 0;
        sc->vm_ct = 0;
        sc->vm_idx = 0;
 
@@ -1498,6 +1502,15 @@ vm_create(struct vm_create_params *vcp, struct proc *p)
        if (vcp->vcp_ncpus != 1)
                return (EINVAL);
 
+       rw_enter_write(&vmm_softc->vm_lock);
+       if (vmm_softc->vcpu_ct + vcp->vcp_ncpus > VMM_MAX_VCPUS) {
+               DPRINTF("%s: maximum vcpus (%lu) reached\n", __func__,
+                   vmm_softc->vcpu_max);
+               rw_exit_write(&vmm_softc->vm_lock);
+               return (ENOMEM);
+       }
+       vmm_softc->vcpu_ct += vcp->vcp_ncpus;
+
        vm = pool_get(&vm_pool, PR_WAITOK | PR_ZERO);
        SLIST_INIT(&vm->vm_vcpu_list);
        rw_init(&vm->vm_vcpu_lock, "vcpu_list");
@@ -1509,8 +1522,6 @@ vm_create(struct vm_create_params *vcp, struct proc *p)
        vm->vm_memory_size = memsize;
        strncpy(vm->vm_name, vcp->vcp_name, VMM_MAX_NAME_LEN - 1);
 
-       rw_enter_write(&vmm_softc->vm_lock);
-
        if (vm_impl_init(vm, p)) {
                printf("failed to init arch-specific features for vm %p\n", vm);
                vm_teardown(vm);
@@ -3784,6 +3795,7 @@ vm_teardown(struct vm *vm)
                SLIST_REMOVE(&vm->vm_vcpu_list, vcpu, vcpu, vc_vcpu_link);
                vcpu_deinit(vcpu);
                pool_put(&vcpu_pool, vcpu);
+               vmm_softc->vcpu_ct--;
        }
 
        vm_impl_deinit(vm);
index 843df0f..94bb172 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: vmmvar.h,v 1.73 2021/08/31 17:40:59 dv Exp $  */
+/*     $OpenBSD: vmmvar.h,v 1.74 2021/09/13 22:16:27 dv Exp $  */
 /*
  * Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org>
  *
@@ -29,6 +29,7 @@
 #define VMM_MAX_PATH_CDROM     128
 #define VMM_MAX_NAME_LEN       64
 #define VMM_MAX_KERNEL_PATH    128
+#define VMM_MAX_VCPUS          512
 #define VMM_MAX_VCPUS_PER_VM   64
 #define VMM_MAX_VM_MEM_SIZE    32768
 #define VMM_MAX_NICS_PER_VM    4