From 7c1679678ae8696cbd7bb0ef76d1f44611755097 Mon Sep 17 00:00:00 2001 From: Atharv Mantri Date: Mon, 14 Sep 2026 08:45:34 +0530 Subject: [PATCH 1/2] Fix: validate minizip extra field sizes --- contrib/minizip/zip.c | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/contrib/minizip/zip.c b/contrib/minizip/zip.c index 0bbdf77e5f..bb4188595d 100644 --- a/contrib/minizip/zip.c +++ b/contrib/minizip/zip.c @@ -2199,8 +2199,11 @@ extern int ZEXPORT zipRemoveExtraInfoBlock(char* pData, int* dataLen, short sHea int size = 0; char* pNewHeader; char* pTmp; - short header; - short dataSize; + char* end; + unsigned short header; + unsigned short dataSize; + unsigned int blockSize; + size_t remaining; int retVal = ZIP_OK; @@ -2208,23 +2211,39 @@ extern int ZEXPORT zipRemoveExtraInfoBlock(char* pData, int* dataLen, short sHea return ZIP_PARAMERROR; pNewHeader = (char*)ALLOC((unsigned)*dataLen); + if (pNewHeader == NULL) + return ZIP_INTERNALERROR; pTmp = pNewHeader; + end = pData + *dataLen; - while(p < (pData + *dataLen)) + while(p < end) { - header = *(short*)p; - dataSize = *(((short*)p)+1); + remaining = (size_t)(end - p); + if (remaining < 4) + { + retVal = ZIP_PARAMERROR; + goto cleanup; + } + + header = *(unsigned short*)p; + dataSize = *(((unsigned short*)p)+1); + blockSize = (unsigned int)dataSize + 4; + if (blockSize > remaining) + { + retVal = ZIP_PARAMERROR; + goto cleanup; + } if( header == sHeader ) /* Header found. */ { - p += dataSize + 4; /* skip it. do not copy to temp buffer */ + p += blockSize; /* skip it. do not copy to temp buffer */ } else { /* Extra Info block should not be removed, So copy it to the temp buffer. */ - memcpy(pTmp, p, dataSize + 4); - p += dataSize + 4; - size += dataSize + 4; + memcpy(pTmp, p, blockSize); + p += blockSize; + size += blockSize; } } @@ -2246,6 +2265,7 @@ extern int ZEXPORT zipRemoveExtraInfoBlock(char* pData, int* dataLen, short sHea else retVal = ZIP_ERRNO; +cleanup: free(pNewHeader); return retVal; From 846fe76b7bb01879a0b8278d85df56117f08d60d Mon Sep 17 00:00:00 2001 From: Atharv Mantri Date: Tue, 15 Sep 2026 09:28:54 +0530 Subject: [PATCH 2/2] Add extra field bounds regression test --- contrib/minizip/test/CMakeLists.txt | 14 +++++++++ contrib/minizip/test/extra_field_bounds.c | 38 +++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 contrib/minizip/test/extra_field_bounds.c diff --git a/contrib/minizip/test/CMakeLists.txt b/contrib/minizip/test/CMakeLists.txt index a909a24281..67dfe2191e 100644 --- a/contrib/minizip/test/CMakeLists.txt +++ b/contrib/minizip/test/CMakeLists.txt @@ -1,4 +1,18 @@ # if we are built from with zlib, use this path's) + +set(MINIZIP_TEST_LIBRARY MINIZIP::minizipstatic) + +add_executable( + ${ZLIB_CONTRIB_PREFIX}minizip_extra_field_bounds_test + extra_field_bounds.c) +target_link_libraries( + ${ZLIB_CONTRIB_PREFIX}minizip_extra_field_bounds_test + PRIVATE ${MINIZIP_TEST_LIBRARY}) +add_test( + NAME ${ZLIB_CONTRIB_PREFIX}minizip_extra_field_bounds_test + COMMAND ${ZLIB_CONTRIB_PREFIX}minizip_extra_field_bounds_test + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + if(ZLIB_MINIZIP_INSTALL) if(NOT DEFINED ZLIB_BUILD_MINIZIP) set(WORK_DIR ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/contrib/minizip/test/extra_field_bounds.c b/contrib/minizip/test/extra_field_bounds.c new file mode 100644 index 0000000000..f9c9a7e213 --- /dev/null +++ b/contrib/minizip/test/extra_field_bounds.c @@ -0,0 +1,38 @@ +#include +#include + +#include "zip.h" + +static int expect_rejected(char *data, int data_len) { + char original[8]; + int original_len = data_len; + int result; + + memcpy(original, data, (size_t)data_len); + result = zipRemoveExtraInfoBlock(data, &data_len, 0x1234); + if (result != ZIP_PARAMERROR || data_len != original_len || + memcmp(data, original, (size_t)original_len) != 0) { + fprintf(stderr, "malformed extra field was not rejected safely\n"); + return 1; + } + return 0; +} + +int main(void) { + char short_header[] = {0x34, 0x12, 0x00}; + char truncated_block[] = {0x34, 0x12, 0x01, 0x00}; + char valid_block[] = {0x34, 0x12, 0x02, 0x00, (char)0xab, (char)0xcd}; + int valid_len = (int)sizeof(valid_block); + + if (expect_rejected(short_header, (int)sizeof(short_header)) != 0 || + expect_rejected(truncated_block, (int)sizeof(truncated_block)) != 0) + return 1; + + if (zipRemoveExtraInfoBlock(valid_block, &valid_len, 0x1234) != ZIP_OK || + valid_len != 0) { + fprintf(stderr, "valid extra field was not removed\n"); + return 1; + } + + return 0; +}