⬢ DragonFlyBSD Kernel Audit
DF-4900 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/disk/dm/dm_dev.c
+++ b/sys/dev/disk/dm/dm_dev.c
@@ -231,7 +231,18 @@
 	if ((dmv = dm_dev_alloc(name, uuid)) == NULL)
 		return ENOMEM;
 
-	dm_minor = devfs_clone_bitmap_get(&dm_minor_bitmap, 0);
+	/*
+	 * The dev_t minor encoding (dkmakeminor in <sys/diskslice.h>) only
+	 * has room for DKMAXUNITS (512) distinct units.  Handing out unit
+	 * numbers beyond that aliases the minor numbers of live dm devices
+	 * (duplicate device numbers, KKASSERT panic in dm_dev_insert, and
+	 * dkunit() truncation corrupts the clone bitmap on destroy).
+	 */
+	dm_minor = devfs_clone_bitmap_get(&dm_minor_bitmap, DKMAXUNITS - 1);
+	if (dm_minor < 0) {
+		dm_dev_free(dmv);
+		return ENOSPC;
+	}
 
 	dm_table_head_init(&dmv->table_head);
 
@@ -287,7 +298,8 @@
 	devstat_remove_entry(&dmv->stats);
 
 	release_dev(dmv->devt);
-	devfs_clone_bitmap_put(&dm_minor_bitmap, minor);
+	/* dkunit() only decodes DKMAXUNITS worth of unit bits */
+	devfs_clone_bitmap_put(&dm_minor_bitmap, minor & (DKMAXUNITS - 1));
 
 	lockuninit(&dmv->dev_mtx);
 	cv_destroy(&dmv->dev_cv);