DragonFlyBSD Kernel Audit
DF-0804 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/vfs/hammer2/hammer2_strategy.c b/sys/vfs/hammer2/hammer2_strategy.c
index 0000000..1111111 100644
--- a/sys/vfs/hammer2/hammer2_strategy.c
+++ b/sys/vfs/hammer2/hammer2_strategy.c
@@ -448,7 +448,17 @@
 	if (focus->bref.type == HAMMER2_BREF_TYPE_INODE) {
 		/*
 		 * Copy from in-memory inode structure.
+		 *
+		 * Guard against a NULL data pointer (e.g. a corrupted
+		 * bref.data_off of 0 causes chain_load_data to leave
+		 * chain->data NULL without setting an error).
 		 */
+		if (data == NULL) {
+			bp->b_flags |= B_ERROR;
+			bp->b_error = EIO;
+			bp->b_resid = bp->b_bcount;
+			return;
+		}
 		bcopy(((const hammer2_inode_data_t *)data)->u.data,
 		      bp->b_data, HAMMER2_EMBEDDED_BYTES);
 		bzero(bp->b_data + HAMMER2_EMBEDDED_BYTES,
@@ -482,6 +492,14 @@
 							 bio);
 			/* b_resid set by call */
 			break;
+		case HAMMER2_COMP_AUTOZERO:
+			/*
+			 * Block is logically zero; not stored on media.
+			 */
+			bzero(bp->b_data, bp->b_bcount);
+			bp->b_resid = 0;
+			bp->b_error = 0;
+			break;
 		case HAMMER2_COMP_NONE:
 			KKASSERT(focus->bytes <= bp->b_bcount);
 			bcopy(data, bp->b_data, focus->bytes);
@@ -493,11 +511,29 @@
 			bp->b_error = 0;
 			break;
 		default:
-			panic("hammer2_strategy_read_completion: "
-			      "unknown compression type");
+			/*
+			 * Unknown / out-of-range compression method from a
+			 * corrupted or crafted image: report EIO instead of
+			 * panicking the kernel.
+			 */
+			kprintf("hammer2_strategy_read_completion: "
+				"unknown compression type %d\n",
+				HAMMER2_DEC_COMP(focus->bref.methods));
+			bp->b_flags |= B_ERROR;
+			bp->b_error = EIO;
+			bp->b_resid = bp->b_bcount;
+			break;
 		}
 	} else {
-		panic("hammer2_strategy_read_completion: unknown bref type");
+		/*
+		 * Unknown / out-of-range bref type from a corrupted or
+		 * crafted image: report EIO instead of panicking the kernel.
+		 */
+		kprintf("hammer2_strategy_read_completion: unknown bref type %d\n",
+			focus->bref.type);
+		bp->b_flags |= B_ERROR;
+		bp->b_error = EIO;
+		bp->b_resid = bp->b_bcount;
 	}
 }