DragonFlyBSD Kernel Audit
DF-3076 / fix.diff
← back to finding ↓ download raw
--- a/sys/vfs/hammer/hammer_blockmap.c
+++ b/sys/vfs/hammer/hammer_blockmap.c
@@ -783,7 +783,19 @@
 	 * Alignment
 	 */
 	bytes = HAMMER_DATA_DOALIGN(bytes);
-	KKASSERT(bytes <= HAMMER_XBUFSIZE);
+	if (bytes <= 0 || bytes > HAMMER_XBUFSIZE) {
+		/*
+		 * Crafted or corrupt media.  bytes originates from an
+		 * on-disk B-Tree leaf (data_len) e.g. via
+		 * hammer_delete_at_cursor(); applying such a free to the
+		 * freemap would corrupt layer2 bytes_free accounting and
+		 * can force-free a big-block still referenced by other
+		 * records.  Refuse the free instead.
+		 */
+		hdkprintf("blockmap_free: bad bytes %d for %016jx\n",
+			  bytes, (intmax_t)zone_offset);
+		return;
+	}
 	KKASSERT(((zone_offset ^ (zone_offset + (bytes - 1))) &
 		  ~HAMMER_BIGBLOCK_MASK64) == 0);
 
@@ -907,7 +919,15 @@
 	 * Alignment
 	 */
 	bytes = HAMMER_DATA_DOALIGN(bytes);
-	KKASSERT(bytes <= HAMMER_BIGBLOCK_SIZE);
+	if (bytes <= 0 || bytes > HAMMER_BIGBLOCK_SIZE) {
+		/*
+		 * Crafted or corrupt media (data_len from an on-disk
+		 * leaf); refuse rather than wrap layer2 accounting.
+		 */
+		hdkprintf("blockmap_dedup: bad bytes %d for %016jx\n",
+			  bytes, (intmax_t)zone_offset);
+		return (EINVAL);
+	}
 	KKASSERT(((zone_offset ^ (zone_offset + (bytes - 1))) &
 		  ~HAMMER_BIGBLOCK_MASK64) == 0);
 
@@ -1007,7 +1027,16 @@
 	 * Alignment
 	 */
 	bytes = HAMMER_DATA_DOALIGN(bytes);
-	KKASSERT(bytes <= HAMMER_XBUFSIZE);
+	if (bytes <= 0 || bytes > HAMMER_XBUFSIZE) {
+		/*
+		 * Crafted or corrupt media; refuse rather than wrap
+		 * layer2 accounting (note callers currently ignore the
+		 * return value - DF-3014).
+		 */
+		hdkprintf("blockmap_finalize: bad bytes %d for %016jx\n",
+			  bytes, (intmax_t)zone_offset);
+		return (EINVAL);
+	}
 
 	/*
 	 * Basic zone validation & locking