synopse / mORMot

Synopse mORMot 1 ORM/SOA/MVC framework - Please upgrade to mORMot 2 !
https://synopse.info
788 stars 325 forks source link

Infinite loop in SynZip UnCompress (Stream, Mem or ZipString) #403

Closed EricGrange closed 3 years ago

EricGrange commented 3 years ago

Those functions currently contain an infinite loop for some special cases of compressed stream corruption, they have a repeat...until loop which looks like

    repeat
      code := Check(inflate(strm, Z_FINISH),[Z_OK,Z_STREAM_END,Z_BUF_ERROR],'UnCompressStream');
      FlushBuf;
    until code=Z_STREAM_END;

And Check() is thus set to accept Z_BUF_ERROR while the until test does not cover for the case when FlushBuf will not handle it.

To reproduce run the following code on the deflate.bomb file that is inside the attached zip. The issue occurs on both Win32 and Win64.

var
   f : TFileStream;
   buf : TBytes;
   outBuf : ZipString;
begin
   f := TFileStream.Create('c:\temp\deflate.bomb', fmOpenRead);
   SetLength(buf, f.Size);
   f.Read(buf[0], f.Size);
   UnCompressZipString(Pointer(buf), f.Size, outBuf, nil, False, 64*1024);  // never ends
end.

deflate.bomb.zip

synopse commented 3 years ago

I read again the zlib documentation. It states:

Z_BUF_ERROR if no progress is possible or if there was not enough room in the
  output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
  inflate() can be called again with more input and more output space to
  continue decompressing. 

So Z_BUF_ERROR is returned when the output buffer needs to be flushed. This was a weird case when this code is returned... and no output buffer is to be flushed... I guessed that Z_DATA_ERROR would have been returned in such case.

Should be fixed now.

synopse commented 3 years ago

No feedback.

I suspect our fix did the trick. Please reopen or create a new ticket if it was not enough.