DragonFlyBSD Kernel Audit
DF-0952 / fix.diff
← back to finding ↓ download raw
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
@@ -223,8 +223,24 @@
 	error = ENOENT;
 	if ((ve = vkernel_find_vmspace(vkp, uap->id, 1)) != NULL) {
 		error = vmspace_entry_delete(ve, vkp, 1);
+		/*
+		 * DF-0952: vkernel_find_vmspace() bumped ve->refs by 1
+		 * (documented "caller must drop").  On success
+		 * vmspace_entry_delete() consumes that ref atomically
+		 * via the cmpset that installs VKE_REF_DELETED, and we
+		 * then drop the on-tree cache ref via cache_drop.
+		 *
+		 * On EBUSY the cmpset did NOT consume the find's ref, so
+		 * we must drop it explicitly here.  Previously we leaked
+		 * one ref per failed destroy, permanently inflating
+		 * ve->refs until proc-exit's rb_vmspace_delete() called
+		 * vmspace_entry_delete(ve, vkp, 0) and panicked with
+		 * "rb_vmspace_delete: invalid refs N".
+		 */
 		if (error == 0)
 			vmspace_entry_cache_drop(ve);
+		else
+			vmspace_entry_drop(ve);
 	}
 	lwkt_reltoken(&vkp->token);