diff --git a/sys/vfs/hammer/hammer_vnops.c b/sys/vfs/hammer/hammer_vnops.c --- a/sys/vfs/hammer/hammer_vnops.c +++ b/sys/vfs/hammer/hammer_vnops.c @@ -1725,6 +1725,19 @@ break; base = &cursor.leaf->base; saveoff = base->key; + /* + * Validate the on-disk direntry data_len before using it. + * A corrupted or forged B-tree leaf can carry data_len <= + * HAMMER_ENTRY_NAME_OFF, which underflows the name length + * computed below and (on INVARIANTS-OFF kernels) drives a + * ~49 KB out-of-bounds read in vop_write_dirent(). Reject + * any leaf whose data_len is not a plausible direntry size. + */ + if (cursor.leaf->data_len <= HAMMER_ENTRY_NAME_OFF || + cursor.leaf->data_len > HAMMER_ENTRY_NAME_OFF + NAME_MAX) { + error = EIO; + break; + } KKASSERT(cursor.leaf->data_len > HAMMER_ENTRY_NAME_OFF); if (base->obj_id != ip->obj_id)