diff --git a/lua/arti-pack/archive.lua b/lua/arti-pack/archive.lua index 4403602..88e83fc 100644 --- a/lua/arti-pack/archive.lua +++ b/lua/arti-pack/archive.lua @@ -140,6 +140,11 @@ local function zip_entries(buf) if u32(buf, pos) ~= CD_SIG then return nil, 'malformed central directory' end + -- The fixed 46-byte header has to be there in full, otherwise the fields + -- read below are nil and the parse blows up instead of reporting. + if pos + 45 > #buf then + return nil, 'truncated central directory' + end local namelen = u16(buf, pos + 28) local entry = { version_made_by = u16(buf, pos + 4), @@ -166,6 +171,9 @@ local function zip_data(buf, entry) if u32(buf, lho) ~= LOCAL_SIG then return reject(entry.name, 'invalid local header signature') end + if lho + 29 > #buf then + return reject(entry.name, 'truncated local header') + end local start = lho + 30 + u16(buf, lho + 26) + u16(buf, lho + 28) local data @@ -262,6 +270,10 @@ local function pax_records(block) break end len = tonumber(len) + -- A zero length would leave pos where it is and spin forever. + if len < 1 then + break + end local record = block:sub(rest, pos + len - 2) local key, value = record:match('^([^=]+)=(.*)$') if key then