diff --git a/lib/init.luau b/lib/init.luau index c66f9a0..c7e3146 100644 --- a/lib/init.luau +++ b/lib/init.luau @@ -280,14 +280,23 @@ function ZipReader.parseCentralDirectory(self: ZipReader): () -- 20 2 Comment length (n) -- 22 n Comment - local cdOffset = buffer.readu32(self.data, pos + 16) + local cdSize = buffer.readu32(self.data, pos + 12) local cdEntries = buffer.readu16(self.data, pos + 10) - local cdCommentLength = buffer.readu16(self.data, pos + 20) - self.comment = buffer.readstring(self.data, pos + 22, cdCommentLength) + local cdOffset = buffer.readu32(self.data, pos + 16) - -- Process each entry in the Central Directory + -- Strict validation of CD boundaries and entry count + if cdOffset >= bufSize or cdOffset + cdSize > bufSize then + error("Invalid Central Directory offset or size") + end + + -- Track actual entries found + local entriesFound = 0 pos = cdOffset - for i = 1, cdEntries do + while pos < cdOffset + cdSize do + if buffer.readu32(self.data, pos) ~= SIGNATURES.CENTRAL_DIR then + error("Invalid Central Directory entry signature") + end + -- Central Directory Entry format: -- Offset Bytes Description -- 0 4 Central directory entry signature @@ -338,7 +347,15 @@ function ZipReader.parseCentralDirectory(self: ZipReader): () ) pos = pos + 46 + nameLength + extraLength + commentLength + entriesFound += 1 end + + if entriesFound ~= cdEntries then + error("Found different entries than specified in Central Directory") + end + + local cdCommentLength = buffer.readu16(self.data, pos + 20) + self.comment = buffer.readstring(self.data, pos + 22, cdCommentLength) end function ZipReader.buildDirectoryTree(self: ZipReader): () diff --git a/tests/extract.luau b/tests/extract.luau index 48b4a6b..8d6ff82 100644 --- a/tests/extract.luau +++ b/tests/extract.luau @@ -10,11 +10,10 @@ local ZipReader = require("../lib") local ZIPS = fs.readDir("tests/data") local FALLIBLES = { "invalid_cde_number_of_files_allocation_greater_offset.zip", - -- FIXME: Incorrectly handled, file tree is empty and walk silently errors - -- "invalid_cde_number_of_files_allocation_smaller_offset.zip", + "invalid_cde_number_of_files_allocation_smaller_offset.zip", "invalid_offset.zip", "invalid_offset2.zip", - "chinese.zip", -- Contains non UTF8 data which can't parse without OS APIs + "chinese.zip", -- Contains non local specific encoding which can't be parsed without OS APIs "non_utf8.zip", -- FIXME: Lune breaks for non utf8 data in process stdout "pandoc_soft_links.zip", -- Soft links are tested separately in edge_cases }