⬢ DragonFlyBSD Kernel Audit
DF-3077 / fix.diff
← back to finding ↓ download raw
--- a/sys/vfs/hammer/hammer_blockmap.c
+++ b/sys/vfs/hammer/hammer_blockmap.c
@@ -134,6 +134,13 @@
 	*errorp = 0;
 	blockmap = &hmp->blockmap[zone];
 	freemap = &hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX];
+	/* DF-3077: validate zone in production too; crafted vol0_blockmap
+	 * next_offset in a foreign zone must not allocate cross-zone. */
+	if (HAMMER_ZONE_DECODE(blockmap->next_offset) != zone) {
+		hmkprintf(hmp, "blockmap zone mismatch for zone %d\n", zone);
+		*errorp = EINVAL;
+		return (0);
+	}
 	KKASSERT(HAMMER_ZONE_DECODE(blockmap->next_offset) == zone);
 
 	/*
@@ -159,7 +166,7 @@
 	/*
 	 * Check for wrap
 	 */
-	if (next_offset == HAMMER_ZONE_ENCODE(zone + 1, 0)) {
+	if (next_offset >= HAMMER_ZONE_ENCODE(zone + 1, 0)) {	/* DF-3077: >= */
 		if (++loops == 2) {
 			hmkprintf(hmp, "No space left for zone %d "
 				"allocation\n", zone);
@@ -446,6 +453,13 @@
 		return(NULL);
 	blockmap = &hmp->blockmap[zone];
 	freemap = &hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX];
+	/* DF-3077: validate zone in production too; crafted vol0_blockmap
+	 * next_offset in a foreign zone must not allocate cross-zone. */
+	if (HAMMER_ZONE_DECODE(blockmap->next_offset) != zone) {
+		hmkprintf(hmp, "blockmap zone mismatch for zone %d\n", zone);
+		*errorp = EINVAL;
+		return (0);
+	}
 	KKASSERT(HAMMER_ZONE_DECODE(blockmap->next_offset) == zone);
 
 	/*
@@ -463,7 +477,7 @@
 	/*
 	 * Check for wrap
 	 */
-	if (next_offset == HAMMER_ZONE_ENCODE(zone + 1, 0)) {
+	if (next_offset >= HAMMER_ZONE_ENCODE(zone + 1, 0)) {	/* DF-3077: >= */
 		if (++loops == 2) {
 			hmkprintf(hmp, "No space left for zone %d "
 				"reservation\n", zone);