Improved defenses against corrupt ZIP archives in the zipfile extension

3 months ago 2

Overview

Context

Changes

112 113 114 115 116 117 118 119 120 121 122 123 124 125 "data," /* 5: Uncompressed data */ "method," /* 6: Compression method (integer) */ "z HIDDEN" /* 7: Name of zip file */ ") WITHOUT ROWID;"; #define ZIPFILE_F_COLUMN_IDX 7 /* Index of column "file" in the above */ #define ZIPFILE_BUFFER_SIZE (64*1024) /* ** Magic numbers used to read and write zip files. ** ** ZIPFILE_NEWENTRY_MADEBY: ** Use this value for the "version-made-by" field in new zip file > 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 "data," /* 5: Uncompressed data */ "method," /* 6: Compression method (integer) */ "z HIDDEN" /* 7: Name of zip file */ ") WITHOUT ROWID;"; #define ZIPFILE_F_COLUMN_IDX 7 /* Index of column "file" in the above */ #define ZIPFILE_BUFFER_SIZE (64*1024) #define ZIPFILE_MX_NAME (250) /* Windows limitation on filename size */ /* ** Magic numbers used to read and write zip files. ** ** ZIPFILE_NEWENTRY_MADEBY: ** Use this value for the "version-made-by" field in new zip file
668 669 670 671 672 673 674 675 676 677 678 679 680 681 pLFH->mTime = zipfileRead16(aRead); pLFH->mDate = zipfileRead16(aRead); pLFH->crc32 = zipfileRead32(aRead); pLFH->szCompressed = zipfileRead32(aRead); pLFH->szUncompressed = zipfileRead32(aRead); pLFH->nFile = zipfileRead16(aRead); pLFH->nExtra = zipfileRead16(aRead); } return rc; } /* ** Buffer aExtra (size nExtra bytes) contains zip archive "extra" fields. > 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 pLFH->mTime = zipfileRead16(aRead); pLFH->mDate = zipfileRead16(aRead); pLFH->crc32 = zipfileRead32(aRead); pLFH->szCompressed = zipfileRead32(aRead); pLFH->szUncompressed = zipfileRead32(aRead); pLFH->nFile = zipfileRead16(aRead); pLFH->nExtra = zipfileRead16(aRead); if( pLFH->nFile>ZIPFILE_MX_NAME ) rc = SQLITE_ERROR; } return rc; } /* ** Buffer aExtra (size nExtra bytes) contains zip archive "extra" fields.
881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 } if( rc==SQLITE_OK ) rc = zipfileReadLFH(aRead, &lfh); if( rc==SQLITE_OK ){ pNew->iDataOff = pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ; pNew->iDataOff += lfh.nFile + lfh.nExtra; if( aBlob && pNew->cds.szCompressed ){ pNew->aData = &pNew->aExtra[nExtra]; memcpy(pNew->aData, &aBlob[pNew->iDataOff], pNew->cds.szCompressed); } }else{ *pzErr = sqlite3_mprintf("failed to read LFH at offset %d", (int)pNew->cds.iOffset ); } } > > > | | > 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 } if( rc==SQLITE_OK ) rc = zipfileReadLFH(aRead, &lfh); if( rc==SQLITE_OK ){ pNew->iDataOff = pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ; pNew->iDataOff += lfh.nFile + lfh.nExtra; if( aBlob && pNew->cds.szCompressed ){ if( pNew->iDataOff + pNew->cds.szCompressed > nBlob ){ rc = SQLITE_CORRUPT; }else{ pNew->aData = &pNew->aExtra[nExtra]; memcpy(pNew->aData, &aBlob[pNew->iDataOff], pNew->cds.szCompressed); } } }else{ *pzErr = sqlite3_mprintf("failed to read LFH at offset %d", (int)pNew->cds.iOffset ); } }
1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 rc = zipfileGetMode(apVal[3], bIsDir, &mode, &pTab->base.zErrMsg); } if( rc==SQLITE_OK ){ zPath = (const char*)sqlite3_value_text(apVal[2]); if( zPath==0 ) zPath = ""; nPath = (int)strlen(zPath); mTime = zipfileGetTime(apVal[4]); } if( rc==SQLITE_OK && bIsDir ){ /* For a directory, check that the last character in the path is a ** '/'. This appears to be required for compatibility with info-zip ** (the unzip command on unix). It does not create directories > > > > > 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 rc = zipfileGetMode(apVal[3], bIsDir, &mode, &pTab->base.zErrMsg); } if( rc==SQLITE_OK ){ zPath = (const char*)sqlite3_value_text(apVal[2]); if( zPath==0 ) zPath = ""; nPath = (int)strlen(zPath); if( nPath>ZIPFILE_MX_NAME ){ zipfileTableErr(pTab, "filename too long; max: %d bytes", ZIPFILE_MX_NAME); rc = SQLITE_CONSTRAINT; } mTime = zipfileGetTime(apVal[4]); } if( rc==SQLITE_OK && bIsDir ){ /* For a directory, check that the last character in the path is a ** '/'. This appears to be required for compatibility with info-zip ** (the unzip command on unix). It does not create directories
2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 /* Check that the 'name' parameter looks ok. */ zName = (char*)sqlite3_value_text(pName); nName = sqlite3_value_bytes(pName); if( zName==0 ){ zErr = sqlite3_mprintf("first argument to zipfile() must be non-NULL"); rc = SQLITE_ERROR; goto zipfile_step_out; } /* Inspect the 'method' parameter. This must be either 0 (store), 8 (use ** deflate compression) or NULL (choose automatically). */ if( pMethod && SQLITE_NULL!=sqlite3_value_type(pMethod) ){ iMethod = (int)sqlite3_value_int64(pMethod); if( iMethod!=0 && iMethod!=8 ){ > > > > > > > 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 /* Check that the 'name' parameter looks ok. */ zName = (char*)sqlite3_value_text(pName); nName = sqlite3_value_bytes(pName); if( zName==0 ){ zErr = sqlite3_mprintf("first argument to zipfile() must be non-NULL"); rc = SQLITE_ERROR; goto zipfile_step_out; } if( nName>ZIPFILE_MX_NAME ){ zErr = sqlite3_mprintf( "filename argument to zipfile() too big; max: %d bytes", ZIPFILE_MX_NAME); rc = SQLITE_ERROR; goto zipfile_step_out; } /* Inspect the 'method' parameter. This must be either 0 (store), 8 (use ** deflate compression) or NULL (choose automatically). */ if( pMethod && SQLITE_NULL!=sqlite3_value_type(pMethod) ){ iMethod = (int)sqlite3_value_int64(pMethod); if( iMethod!=0 && iMethod!=8 ){
Read Entire Article