⬢ DragonFlyBSD Kernel Audit
DF-4907 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/disk/dm/delay/dm_target_delay.c
+++ b/sys/dev/disk/dm/delay/dm_target_delay.c
@@ -303,7 +303,26 @@
 
 	while ((dp = TAILQ_FIRST(&tmp_list)) != NULL) {
 		TAILQ_REMOVE(&tmp_list, dp, entry);
-		_submit(di, dp->bp);
+		if (submit_all) {
+			/*
+			 * Target teardown (dm_target_delay_destroy): do NOT
+			 * submit these bios to the pdev.  vn_strategy() is
+			 * asynchronous, so the bios would still be in flight
+			 * after _destroy() returns and after the enclosing
+			 * dm device may have been freed by dm_dev_destroy().
+			 * Their completion path (nestiobuf_iodone ->
+			 * nestiobuf_done -> devstat_end_transaction_buf)
+			 * then writes through the captured &dmv->stats into
+			 * freed (and typically reallocated) kernel memory.
+			 * Fail the queued bios instead; erroring I/O on a
+			 * device being removed is the expected semantic.
+			 */
+			dp->bp->b_error = ENXIO;
+			dp->bp->b_resid = dp->bp->b_bcount;
+			biodone(&dp->bp->b_bio1);
+		} else {
+			_submit(di, dp->bp);
+		}
 		objcache_put(obj_cache, dp);
 	}
 }