DF-0850 / fix.diff
diff --git a/sys/vfs/ext2fs/ext2_htree.c b/sys/vfs/ext2fs/ext2_htree.c --- a/sys/vfs/ext2fs/ext2_htree.c +++ b/sys/vfs/ext2fs/ext2_htree.c @@ -331,12 +331,30 @@ level_info->h_entry = found; if (levels == 0) return (0); + /* + * Reject descent into block 0 (the directory root, already + * locked above). A crafted image can set a htree entry's + * block to 0, causing ext2_blkatoff to re-lock the root + * buffer and panic with "lockmgr: locking against myself". + */ + if (ext2_htree_get_block(found) == 0) + goto error; levels--; if (ext2_blkatoff(vp, ext2_htree_get_block(found) * m_fs->e2fs_bsize, NULL, &bp) != 0) goto error; entp = ((struct ext2fs_htree_node *)bp->b_data)->h_entries; + /* + * Validate the interior node's limit field against the + * filesystem-computed limit, mirroring the root-level check + * above. Without this, an attacker-controlled on-disk limit + * (e.g. 0xFFFF) defeats the cnt > get_limit() guard on the + * next iteration, allowing an OOB binary-search read past + * the bp->b_data buffer and a subsequent bogus block lookup. + */ + if (ext2_htree_get_limit(entp) != ext2_htree_node_limit(ip)) + goto error; info->h_levels_num++; info->h_levels[info->h_levels_num - 1].h_bp = bp; } |