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