DragonFlyBSD Kernel Audit
DF-2938 / fix.diff
← back to finding ↓ download raw
--- sys/vm/device_pager.c.orig
+++ sys/vm/device_pager.c
@@ -145,6 +145,15 @@
 		 */
 		if (ops->cdev_pg_ctor == old_dev_pager_ctor) {
 			dev = handle;
+			/*
+			 * DF-2938: the OBJT_DEVICE pager object must pin
+			 * the cdev.  A mapping can outlive every other
+			 * reference (close of the fd, driver teardown,
+			 * clone GC, USB unplug); without this reference
+			 * old_dev_pager_fault()/old_dev_pager_dtor()
+			 * operate on freed memory.
+			 */
+			reference_dev(dev);
 			dev->si_object = object;
 		}
 
@@ -342,6 +351,12 @@
 	if (dev != NULL) {
 		KKASSERT(dev->si_object);
 		dev->si_object = NULL;
+		/*
+		 * DF-2938: drop the reference cdev_pager_allocate()
+		 * took when it created the object for this device
+		 * (runs exactly once per pager object).
+		 */
+		release_dev(dev);
 	}
 }