⬢ DragonFlyBSD Kernel Audit
DF-2835 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/sys/vkernel.h b/sys/sys/vkernel.h
--- a/sys/sys/vkernel.h
+++ b/sys/sys/vkernel.h
+++ b/sys/sys/vkernel.h
@@ -88,6 +88,7 @@
 	struct lwkt_token token;
 	int refs;
 	register_t vkernel_cr3;
+	int nvmspaces;			/* live vmspace entries (DF-2834) */
 };
 
 struct vmspace_entry {
diff --git a/sys/vm/vm_vmspace.c b/sys/vm/vm_vmspace.c
--- a/sys/vm/vm_vmspace.c
+++ b/sys/vm/vm_vmspace.c
@@ -65,6 +65,17 @@
 static MALLOC_DEFINE(M_VKERNEL, "vkernel", "VKernel structures");
 
 /*
+ * Safety cap on live vmspaces per vkernel process (DF-2834).  Each
+ * vmspace pins a wired PML4 page + KVA + slab until destroyed, so an
+ * uncapped vmspace_create() loop is an unprivileged kernel-memory
+ * exhaustion primitive.  Mirrors the vm.max_proc_mmap pattern.
+ */
+static int max_vkernel_vmspaces = 64;
+SYSCTL_INT(_vm, OID_AUTO, max_vkernel_vmspaces, CTLFLAG_RW,
+	   &max_vkernel_vmspaces, 0,
+	   "Maximum number of vmspaces per vkernel process");
+
+/*
  * Cache helper, enter ve into per-lwp cache (avoid vkp->token use)
  */
 static
@@ -155,6 +166,10 @@
 	if (vkernel_enable == 0)
 		return (EOPNOTSUPP);
 
+	/* Enforce the documented ABI (DF-2835), see comment above */
+	if (uap->id == NULL || uap->type != 0 || uap->data != NULL)
+		return (EINVAL);
+
 	/*
 	 * Create a virtual kernel side-structure for the process if one
 	 * does not exist.
@@ -187,6 +202,13 @@
 	pmap_pinit2(vmspace_pmap(ve->vmspace));
 
 	lwkt_gettoken(&vkp->token);
+	if (vkp->nvmspaces >= max_vkernel_vmspaces) {
+		lwkt_reltoken(&vkp->token);
+		vmspace_rel(ve->vmspace);
+		ve->vmspace = NULL; /* safety */
+		kfree(ve, M_VKERNEL);
+		return (ETOOMANYREFS);
+	}
 	if (RB_INSERT(vmspace_rb_tree, &vkp->root, ve)) {
 		vmspace_rel(ve->vmspace);
 		ve->vmspace = NULL; /* safety */
@@ -194,6 +216,7 @@
 		error = EEXIST;
 	} else {
 		error = 0;
+		++vkp->nvmspaces;
 	}
 	lwkt_reltoken(&vkp->token);
 
@@ -641,6 +664,7 @@
 		return EBUSY;
 	}
 	RB_REMOVE(vmspace_rb_tree, &vkp->root, ve);
+	--vkp->nvmspaces;
 
 	/*
 	 * Shouldn't be any other references so we can drop the token