DragonFlyBSD Kernel Audit
DF-1843 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/disk/dm/device-mapper.c b/sys/dev/disk/dm/device-mapper.c
--- a/sys/dev/disk/dm/device-mapper.c
+++ b/sys/dev/disk/dm/device-mapper.c
@@ -209,8 +209,12 @@
 	if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL)
 		return ENXIO;
 
+	/* Hold the busy reference for the lifetime of the open.  Previously
+	 * dmopen called dm_dev_unbusy immediately, leaving the open fd with
+	 * dev->si_drv1 -> dmv but no refcount.  dm_dev_remove_ioctl could
+	 * then race is_open=0, free the dmv, and leave a UAF for the next
+	 * dmstrategy.  The matching extra dm_dev_unbusy is in dmclose. */
 	dmv->is_open = 1;
-	dm_dev_unbusy(dmv);
 
 	dmdebug("minor=%" PRIu32 "\n", minor(ap->a_head.a_dev));
 	return 0;
@@ -230,6 +234,9 @@
 		return ENXIO;
 
 	dmv->is_open = 0;
+	/* Drop dmopen's held reference first (so disable_dev's ref_cnt==0
+	 * wait can complete in order), then drop this lookup's reference. */
+	dm_dev_unbusy(dmv);
 	dm_dev_unbusy(dmv);
 
 	dmdebug("minor=%" PRIu32 "\n", minor(ap->a_head.a_dev));