--- 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);