Skip to content

Commit 75536de

Browse files
authored
Improve ZipUtils::decompressGZ (#2544)
- Fix decompressGZ inf-loop when input data invalid - Valid input size - Parsing uncompress size and reserve exactly avoid waste memory
1 parent 6ab3641 commit 75536de

File tree

2 files changed

+74
-77
lines changed

2 files changed

+74
-77
lines changed

core/base/ZipUtils.cpp

Lines changed: 72 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252

5353
// minizip 1.2.0 is same with other platforms
5454
#define unzGoToFirstFile64(A, B, C, D) unzGoToFirstFile2(A, B, C, D, NULL, 0, NULL, 0)
55-
#define unzGoToNextFile64(A, B, C, D) unzGoToNextFile2(A, B, C, D, NULL, 0, NULL, 0)
55+
#define unzGoToNextFile64(A, B, C, D) unzGoToNextFile2(A, B, C, D, NULL, 0, NULL, 0)
5656

5757
namespace ax
5858
{
@@ -93,32 +93,22 @@ yasio::byte_buffer ZipUtils::compressGZ(const void* in, size_t inlen, int level)
9393
break;
9494
}
9595

96-
switch (err)
97-
{
98-
case Z_NEED_DICT:
99-
err = Z_DATA_ERROR;
100-
case Z_DATA_ERROR:
101-
case Z_MEM_ERROR:
102-
goto _L_end;
103-
}
104-
105-
// not enough buffer ?
106-
if (err != Z_STREAM_END)
96+
if (!err)
10797
{
10898
output.insert(output.end(), buffer, buffer + sizeof(buffer));
10999

110100
d_stream.next_out = buffer;
111101
d_stream.avail_out = sizeof(buffer);
112102
}
103+
else
104+
{
105+
output.clear();
106+
output.shrink_to_fit();
107+
break;
108+
}
113109
}
114110

115-
_L_end:
116111
deflateEnd(&d_stream);
117-
if (err != Z_STREAM_END)
118-
{
119-
output.clear();
120-
}
121-
122112
return output;
123113
}
124114

@@ -141,7 +131,21 @@ yasio::byte_buffer ZipUtils::decompressGZ(const void* in, size_t inlen, int expe
141131
if (err != Z_OK) //
142132
return output;
143133

144-
output.reserve(expected_size != -1 ? expected_size : (inlen << 2));
134+
// GZ contains extra data: crc32(4bytes) + uncompress size(4bytes)
135+
// so at least 8bytes
136+
if (inlen < 8)
137+
{
138+
AXLOGW("ZipUtils: Invalid gz compress data!");
139+
return output;
140+
}
141+
142+
if (expected_size < 1)
143+
{
144+
// gzip: extra data contains crc32(4bytes), uncompress size(4bytes)
145+
memcpy(&expected_size, reinterpret_cast<const uint8_t*>(in) + inlen - 4, 4);
146+
expected_size = std::clamp(expected_size, 1, 20 * 1024 * 1024);
147+
}
148+
output.reserve(expected_size);
145149

146150
for (;;)
147151
{
@@ -153,52 +157,39 @@ yasio::byte_buffer ZipUtils::decompressGZ(const void* in, size_t inlen, int expe
153157
break;
154158
}
155159

156-
switch (err)
160+
if (!err)
157161
{
158-
case Z_NEED_DICT:
159-
err = Z_DATA_ERROR;
160-
case Z_DATA_ERROR:
161-
case Z_MEM_ERROR:
162-
goto _L_end;
163-
}
164-
165-
// not enough memory ?
166-
if (err != Z_STREAM_END)
167-
{
168-
// *out = (unsigned char*)realloc(*out, bufferSize * BUFFER_INC_FACTOR);
169162
output.insert(output.end(), buffer, buffer + sizeof(buffer));
170-
171163
d_stream.next_out = buffer;
172164
d_stream.avail_out = sizeof(buffer);
173165
}
174-
}
175-
176-
_L_end:
177-
inflateEnd(&d_stream);
178-
if (err != Z_STREAM_END)
179-
{
180-
switch (err)
166+
else
181167
{
182-
case Z_MEM_ERROR:
183-
AXLOGW("ZipUtils: Out of memory while decompressing map data!");
184-
break;
185-
case Z_VERSION_ERROR:
186-
AXLOGW("ZipUtils: Incompatible zlib version!");
187-
break;
188-
case Z_DATA_ERROR:
189-
AXLOGW("ZipUtils: Incorrect zlib compressed data!");
168+
switch (err)
169+
{
170+
case Z_MEM_ERROR:
171+
AXLOGW("ZipUtils: Out of memory while decompressing map data!");
172+
break;
173+
case Z_VERSION_ERROR:
174+
AXLOGW("ZipUtils: Incompatible zlib version!");
175+
break;
176+
case Z_DATA_ERROR:
177+
AXLOGW("ZipUtils: Incorrect zlib compressed data!");
178+
break;
179+
default:
180+
AXLOGW("ZipUtils: Decompress data fail, err:{}", err);
181+
}
182+
output.clear();
183+
output.shrink_to_fit();
190184
break;
191-
default:
192-
AXLOGW("ZipUtils: Unknown error while decompressing map data!");
193185
}
194-
output.clear();
195-
output.shrink_to_fit();
196186
}
197187

188+
inflateEnd(&d_stream);
198189
return output;
199190
}
200191

201-
inline void ZipUtils::decodeEncodedPvr(unsigned int* data, ssize_t len)
192+
void ZipUtils::decodeEncodedPvr(unsigned int* data, ssize_t len)
202193
{
203194
const int enclen = 1024;
204195
const int securelen = 512;
@@ -230,7 +221,7 @@ inline void ZipUtils::decodeEncodedPvr(unsigned int* data, ssize_t len)
230221
do
231222
{
232223
#define DELTA 0x9e3779b9
233-
#define MX (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (s_uEncryptedPvrKeyParts[(p & 3) ^ e] ^ z)))
224+
#define MX (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (s_uEncryptedPvrKeyParts[(p & 3) ^ e] ^ z)))
234225

235226
sum += DELTA;
236227
e = (sum >> 2) & 3;
@@ -275,7 +266,7 @@ inline void ZipUtils::decodeEncodedPvr(unsigned int* data, ssize_t len)
275266
}
276267
}
277268

278-
inline unsigned int ZipUtils::checksumPvr(const unsigned int* data, ssize_t len)
269+
unsigned int ZipUtils::checksumPvr(const unsigned int* data, ssize_t len)
279270
{
280271
unsigned int cs = 0;
281272
const int cslen = 128;
@@ -295,7 +286,7 @@ ssize_t ZipUtils::inflateMemoryWithHint(unsigned char* in, ssize_t inLength, uns
295286
auto outBuffer = decompressGZ(std::span{in, in + inLength}, static_cast<int>(outLengthHint));
296287
auto outLen = outBuffer.size();
297288
if (out)
298-
*out = outBuffer.release_pointer();
289+
*out = outBuffer.release_pointer();
299290
return outLen;
300291
}
301292

@@ -347,7 +338,6 @@ int ZipUtils::inflateGZipFile(const char* path, unsigned char** out)
347338
AXLOGW("ZipUtils: gzclose failed");
348339
}
349340

350-
351341
auto totalSize = buffer.size();
352342
if (out)
353343
*out = buffer.release_pointer();
@@ -548,15 +538,15 @@ struct ZipFilePrivate
548538
{
549539
ZipFilePrivate()
550540
{
551-
functionOverrides.zopen64_file = ZipFile_open_file_func;
541+
functionOverrides.zopen64_file = ZipFile_open_file_func;
552542
functionOverrides.zopendisk64_file = ZipFile_opendisk_file_func;
553-
functionOverrides.zread_file = ZipFile_read_file_func;
554-
functionOverrides.zwrite_file = ZipFile_write_file_func;
543+
functionOverrides.zread_file = ZipFile_read_file_func;
544+
functionOverrides.zwrite_file = ZipFile_write_file_func;
555545
functionOverrides.ztell64_file = ZipFile_tell_file_func;
556546
functionOverrides.zseek64_file = ZipFile_seek_file_func;
557-
functionOverrides.zclose_file = ZipFile_close_file_func;
558-
functionOverrides.zerror_file = ZipFile_error_file_func;
559-
functionOverrides.opaque = this;
547+
functionOverrides.zclose_file = ZipFile_close_file_func;
548+
functionOverrides.zerror_file = ZipFile_error_file_func;
549+
functionOverrides.opaque = this;
560550
}
561551

562552
// unzip overrides to support IFileStream
@@ -685,12 +675,15 @@ ZipFile* ZipFile::createFromFile(std::string_view zipFile, std::string_view filt
685675
return nullptr;
686676
}
687677

688-
ZipFile *ZipFile::createWithBuffer(const void* buffer, uLong size)
678+
ZipFile* ZipFile::createWithBuffer(const void* buffer, uLong size)
689679
{
690-
ZipFile *zip = new ZipFile();
691-
if (zip->initWithBuffer(buffer, size)) {
680+
ZipFile* zip = new ZipFile();
681+
if (zip->initWithBuffer(buffer, size))
682+
{
692683
return zip;
693-
} else {
684+
}
685+
else
686+
{
694687
delete zip;
695688
return nullptr;
696689
}
@@ -872,17 +865,21 @@ int ZipFile::getCurrentFileInfo(std::string* filename, unz_file_info_s* info)
872865
return ret;
873866
}
874867

875-
bool ZipFile::initWithBuffer(const void *buffer, uLong size)
868+
bool ZipFile::initWithBuffer(const void* buffer, uLong size)
876869
{
877-
if (!buffer || size == 0) return false;
878-
zlib_filefunc_def memory_file = { 0 };
879-
880-
std::unique_ptr<ourmemory_t> memfs(new ourmemory_t{ (char*)const_cast<void*>(buffer), static_cast<uint32_t>(size), 0, 0, 0 });
881-
if (!memfs) return false;
870+
if (!buffer || size == 0)
871+
return false;
872+
zlib_filefunc_def memory_file = {0};
873+
874+
std::unique_ptr<ourmemory_t> memfs(
875+
new ourmemory_t{(char*)const_cast<void*>(buffer), static_cast<uint32_t>(size), 0, 0, 0});
876+
if (!memfs)
877+
return false;
882878
fill_memory_filefunc(&memory_file, memfs.get());
883-
879+
884880
_data->zipFile = unzOpen2(nullptr, &memory_file);
885-
if (!_data->zipFile) return false;
881+
if (!_data->zipFile)
882+
return false;
886883
_data->memfs = std::move(memfs);
887884
setFilter(emptyFilename);
888885
return true;
@@ -964,4 +961,4 @@ int64_t ZipFile::vsize(ZipEntryInfo* entry)
964961
return 0;
965962
}
966963

967-
}
964+
} // namespace ax

core/base/ZipUtils.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,8 @@ class AX_DLL ZipUtils
231231
unsigned char** out,
232232
ssize_t* outLength,
233233
ssize_t outLengthHint);
234-
static inline void decodeEncodedPvr(unsigned int* data, ssize_t len);
235-
static inline unsigned int checksumPvr(const unsigned int* data, ssize_t len);
234+
static void decodeEncodedPvr(unsigned int* data, ssize_t len);
235+
static unsigned int checksumPvr(const unsigned int* data, ssize_t len);
236236

237237
static unsigned int s_uEncryptedPvrKeyParts[4];
238238
static unsigned int s_uEncryptionKey[1024];

0 commit comments

Comments
 (0)