DragonFlyBSD Kernel Audit
DF-0945 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/vm/vm_swap.c b/sys/vm/vm_swap.c
index 0000000..1111111 100644
--- a/sys/vm/vm_swap.c
+++ b/sys/vm/vm_swap.c
@@ -411,6 +411,17 @@
 	if (error)
 		return (error);
 
+	/*
+	 * Acquire vm_token before swap_mtx to serialize blist tree
+	 * mutations against the swap pager's swp_pager_getswapspace()/
+	 * swp_pager_freeswapspace(), which also hold vm_token.  Without
+	 * this, swapoff_one()'s blist_fill()/blist_destroy()/blist_resize()
+	 * race with concurrent blist_allocat()/blist_free() and corrupt
+	 * the global swapblist radix tree.
+	 *
+	 * Lock order matches swaponvp(): vm_token outer, swap_mtx inner.
+	 */
+	lwkt_gettoken(&vm_token);
 	mtx_lock(&swap_mtx);
 	vp = NULL;
 	error = nlookup_init(&nd, uap->name, UIO_USERSPACE, NLC_FOLLOW);
@@ -434,6 +445,7 @@
 
 done:
 	mtx_unlock(&swap_mtx);
+	lwkt_reltoken(&vm_token);
 	return (error);
 }