DragonFlyBSD Kernel Audit
DF-2661 / fix_b.diff
← back to finding ↓ download raw
--- a/sys/vfs/hammer2/hammer2_io.c
+++ b/sys/vfs/hammer2/hammer2_io.c
@@ -353,14 +353,26 @@
 		dio->bp->b_flags &= ~B_AGE;
 		/* dio->bp->b_debug_info2 = dio; */
 	}
 	if (hammer2_df2661_fail_inode_read > 0 &&
 	    btype == HAMMER2_BREF_TYPE_INODE &&
 	    hmp->voldata.volu_size == 0x20000000ULL) {
 		/* DF-2661 fault injection: only the 512MB test volume,
 		 * never the guest root fs */
 		--hammer2_df2661_fail_inode_read;
 		error = EIO;
 	}
 	dio->error = error;
+	/*
+	 * DF-2661: If the I/O failed, dispose of the buffer now.  Leaving
+	 * dio->bp set with DIO_GOOD clear violates the DIO state machine:
+	 * any subsequent accessor that acquires DIO_INPROG expects
+	 * dio->bp == NULL (and asserts it), and on non-INVARIANTS kernels
+	 * the DOP_NEW path would overwrite the pointer without releasing
+	 * the buffer, orphaning a buffer-lock.
+	 */
+	if (error && dio->bp) {
+		brelse(dio->bp);
+		dio->bp = NULL;
+	}
 
 	/*
 	 * Clear INPROG and WAITING, set GOOD wake up anyone waiting.