⬢ DragonFlyBSD Kernel Audit
DF-5814 / fix.diff
← back to finding ↓ download raw
--- a/sys/vm/vm_pageout.c	2026-10-13 03:47:49.422426023 +0000
+++ b/sys/vm/vm_pageout.c	2026-10-13 03:51:24.815615288 +0000
@@ -1244,6 +1244,7 @@
 		 */
 		if (object->type == OBJT_VNODE) {
 			int flags;
+			int mightbedirty;
 
 			vp = object->handle;
 			flags = LK_EXCLUSIVE;
@@ -1251,6 +1252,15 @@
 				flags |= LK_NOWAIT;
 			else
 				flags |= LK_TIMELOCK;
+			/*
+			 * Sample OBJ_MIGHTBEDIRTY while (m) is still busied:
+			 * the object is provably alive under the page busy.
+			 * After the wakeup/vget window below the object can
+			 * have been terminated and freed (vget failure leaves
+			 * us holding no vnode reference), making any later
+			 * 'object->flags' dereference a use-after-free read.
+			 */
+			mightbedirty = (object->flags & OBJ_MIGHTBEDIRTY) != 0;
 			vm_page_hold(m);
 			vm_page_wakeup(m);
 
@@ -1262,7 +1272,7 @@
 			if (vget(vp, flags) != 0) {
 				*vpfailedp = vp;
 				++pageout_lock_miss;
-				if (object->flags & OBJ_MIGHTBEDIRTY)
+				if (mightbedirty)
 					    ++*vnodes_skippedp;
 				vm_page_unhold(m);
 				return 0;
@@ -1278,7 +1288,7 @@
 			if (m->queue - m->pc != PQ_INACTIVE ||
 			    m->object != object ||
 			    object->handle != vp) {
-				if (object->flags & OBJ_MIGHTBEDIRTY)
+				if (mightbedirty)
 					++*vnodes_skippedp;
 				vput(vp);
 				vm_page_unhold(m);