--- sys/vfs/ext2fs/ext2_htree.c.orig +++ sys/vfs/ext2fs/ext2_htree.c @@ -140,15 +140,30 @@ } while (levels > 0) { + struct ext2fs_htree_entry *nentp; + uint32_t ncnt; + levels--; if (ext2_blkatoff(vp, ext2_htree_get_block(level->h_entry) * ip->i_e2fs->e2fs_bsize, NULL, &bp) != 0) return (0); + /* + * The freshly-read node is unvalidated on-disk metadata: + * apply the sanity checks ext2_htree_find_leaf() applies to + * the root (count within an honest limit), otherwise a + * crafted index walks h_entry past the end of the buffer. + */ + nentp = ((struct ext2fs_htree_node *)bp->b_data)->h_entries; + ncnt = ext2_htree_get_count(nentp); + if (ncnt == 0 || ncnt > ext2_htree_get_limit(nentp) || + ext2_htree_get_limit(nentp) != ext2_htree_node_limit(ip)) { + brelse(bp); + return (0); + } level = &info->h_levels[idx + 1]; brelse(level->h_bp); level->h_bp = bp; - level->h_entry = level->h_entries = - ((struct ext2fs_htree_node *)bp->b_data)->h_entries; + level->h_entry = level->h_entries = nentp; } return (1);