⬢ DragonFlyBSD Kernel Audit
DF-3122 / fix.diff
← back to finding ↓ download raw
--- 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);