diff -uprN lcms-1.17/include/lcms.h lcms-1.17fixed/include/lcms.h --- lcms-1.17/include/lcms.h 2007-07-27 12:00:01.000000000 +0200 +++ lcms-1.17fixed/include/lcms.h 2009-02-24 01:07:47.000000000 +0100 @@ -1412,6 +1412,14 @@ LCMS_INLINE void* _cmsMalloc(size_t size return (void*) malloc(size); } +LCMS_INLINE void* _cmsCalloc(size_t nmemb, size_t size) +{ + size_t alloc = nmemb * size; + if (alloc < nmemb || alloc < size) { + return NULL; + } + return _cmsMalloc(alloc); +} LCMS_INLINE void _cmsFree(void *Ptr) { diff -uprN lcms-1.17/src/cmsgamma.c lcms-1.17fixed/src/cmsgamma.c --- lcms-1.17/src/cmsgamma.c 2007-07-27 12:00:02.000000000 +0200 +++ lcms-1.17fixed/src/cmsgamma.c 2009-02-24 01:07:47.000000000 +0100 @@ -114,7 +114,7 @@ LPGAMMATABLE LCMSEXPORT cmsAllocGamma(in LPGAMMATABLE p; size_t size; - if (nEntries > 65530 || nEntries < 0) { + if (nEntries > 65530 || nEntries <= 0) { cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't create gammatable of more than 65530 entries"); return NULL; } diff -uprN lcms-1.17/src/cmsio0.c lcms-1.17fixed/src/cmsio0.c --- lcms-1.17/src/cmsio0.c 2007-07-27 12:00:02.000000000 +0200 +++ lcms-1.17fixed/src/cmsio0.c 2009-02-24 01:07:47.000000000 +0100 @@ -33,7 +33,7 @@ typedef struct { LPBYTE Block; // Points to allocated memory size_t Size; // Size of allocated memory - int Pointer; // Points to current location + size_t Pointer; // Points to current location int FreeBlockOnClose; // As title } FILEMEM; @@ -75,7 +75,17 @@ size_t MemoryRead(LPVOID buffer, size_t FILEMEM* ResData = (FILEMEM*) Icc ->stream; LPBYTE Ptr; size_t len = size * count; + size_t extent = ResData -> Pointer + len; + if (len < size || len < count) { + cmsSignalError(LCMS_ERRC_ABORTED, "Read from memory error. Integer overflow with count / size."); + return 0; + } + + if (extent < len || extent < ResData -> Pointer) { + cmsSignalError(LCMS_ERRC_ABORTED, "Read from memory error. Integer overflow with len."); + return 0; + } if (ResData -> Pointer + len > ResData -> Size){ @@ -104,7 +114,7 @@ LCMSBOOL MemorySeek(struct _lcms_iccprof return TRUE; } - ResData ->Pointer = (DWORD) offset; + ResData ->Pointer = offset; return FALSE; } diff -uprN lcms-1.17/src/cmsio1.c lcms-1.17fixed/src/cmsio1.c --- lcms-1.17/src/cmsio1.c 2007-07-27 12:00:02.000000000 +0200 +++ lcms-1.17fixed/src/cmsio1.c 2009-02-24 01:10:21.000000000 +0100 @@ -260,11 +260,14 @@ void EvalCHRM(LPcmsCIEXYZ Dest, LPMAT3 C // Read profile header and validate it static -LPLCMSICCPROFILE ReadHeader(LPLCMSICCPROFILE Icc, LCMSBOOL lIsFromMemory) +LPLCMSICCPROFILE ReadHeader(LPLCMSICCPROFILE Icc, + LCMSBOOL lIsFromMemory, + DWORD dwSize) { icTag Tag; icHeader Header; icInt32Number TagCount, i; + icUInt32Number extent; if (Icc -> Read(&Header, sizeof(icHeader), 1, Icc) != 1) goto ErrorCleanup; @@ -286,6 +289,10 @@ LPLCMSICCPROFILE ReadHeader(LPLCMSICCPRO if (Header.magic != icMagicNumber) goto ErrorCleanup; + if (dwSize && dwSize != Header.size) { + goto ErrorCleanup; + } + if (Icc ->Read(&TagCount, sizeof(icInt32Number), 1, Icc) != 1) goto ErrorCleanup; @@ -320,7 +327,7 @@ LPLCMSICCPROFILE ReadHeader(LPLCMSICCPRO // Read tag directory - if (TagCount > MAX_TABLE_TAG) { + if (TagCount > MAX_TABLE_TAG || TagCount < 0) { cmsSignalError(LCMS_ERRC_ABORTED, "Too many tags (%d)", TagCount); goto ErrorCleanup; @@ -337,8 +344,9 @@ LPLCMSICCPROFILE ReadHeader(LPLCMSICCPRO AdjustEndianess32((LPBYTE) &Tag.sig); // Signature // Perform some sanity check. Offset + size should fall inside file. - - if (Tag.offset + Tag.size > Header.size) goto ErrorCleanup; + extent = Tag.offset + Tag.size; + if (extent > Header.size || extent < Tag.offset) + goto ErrorCleanup; Icc -> TagNames[i] = Tag.sig; Icc -> TagOffsets[i] = Tag.offset; @@ -363,7 +371,32 @@ ErrorCleanup: } +int +validateNewLUT(LPLUT NewLUT) { + unsigned int calc = 1; + unsigned int oldCalc; + unsigned int power = NewLUT -> InputChan; + + if (NewLUT -> cLutPoints > 100) NewLUT ->cLutPoints = 100; + if (NewLUT -> InputChan > MAXCHANNELS) NewLUT -> InputChan = MAXCHANNELS; + if (NewLUT -> OutputChan > MAXCHANNELS) NewLUT -> OutputChan = MAXCHANNELS; + + for (; power > 0; power--) { + oldCalc = calc; + calc *= NewLUT -> cLutPoints; + if (calc < oldCalc || calc < NewLUT -> cLutPoints) { + return 0; + } + } + + oldCalc = calc; + calc *= NewLUT -> OutputChan; + if (calc < oldCalc || calc < NewLUT -> OutputChan) { + return 0; + } + return 1; +} static unsigned int uipow(unsigned int a, unsigned int b) { @@ -493,9 +526,9 @@ LCMSBOOL ReadLUT8(LPLCMSICCPROFILE Icc, NewLUT -> OutputEntries = 256; // Do some checking - if (NewLUT -> cLutPoints > 100) NewLUT ->cLutPoints = 100; - if (NewLUT -> InputChan > MAXCHANNELS) NewLUT -> InputChan = MAXCHANNELS; - if (NewLUT -> OutputChan > MAXCHANNELS) NewLUT -> OutputChan = MAXCHANNELS; + if (!validateNewLUT(NewLUT)) { + return FALSE; + } AdjustEndianess32((LPBYTE) &LUT8.e00); AdjustEndianess32((LPBYTE) &LUT8.e01); @@ -570,7 +603,7 @@ LCMSBOOL ReadLUT8(LPLCMSICCPROFILE Icc, if (nTabSize > 0) { - PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * nTabSize); + PtrW = (LPWORD) _cmsCalloc(sizeof(WORD), nTabSize); if (PtrW == NULL) return FALSE; Temp = (LPBYTE) _cmsMalloc(nTabSize); @@ -735,6 +768,9 @@ LCMSBOOL ReadLUT16(LPLCMSICCPROFILE Icc, NewLUT -> InputEntries = LUT16.inputEnt; NewLUT -> OutputEntries = LUT16.outputEnt; + if (!validateNewLUT(NewLUT)) { + return FALSE; + } // Matrix handling @@ -797,7 +833,7 @@ LCMSBOOL ReadLUT16(LPLCMSICCPROFILE Icc, NewLUT->InputChan)); if (nTabSize > 0) { - PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * nTabSize); + PtrW = (LPWORD) _cmsCalloc(sizeof(WORD), nTabSize); if (PtrW == NULL) { _cmsFree(PtrW); return FALSE; @@ -1114,8 +1150,11 @@ LCMSBOOL ReadCLUT(LPLCMSICCPROFILE Icc, if (Icc ->Read(&CLUT, sizeof(icCLutStruct), 1, Icc) != 1) return FALSE; - cmsAlloc3DGrid(NewLUT, CLUT.gridPoints[0], NewLUT ->InputChan, - NewLUT ->OutputChan); + if (cmsAlloc3DGrid(NewLUT, CLUT.gridPoints[0], + NewLUT ->InputChan, + NewLUT ->OutputChan) == NULL) { + return FALSE; + } // Precission can be 1 or 2 bytes @@ -1163,8 +1202,11 @@ LCMSBOOL ReadSetOfCurves(LPLCMSICCPROFIL { LPGAMMATABLE Curves[MAXCHANNELS]; unsigned int i, nCurves; + LCMSBOOL ret = FALSE; if (Icc -> Seek(Icc, Offset)) return FALSE; + + ZeroMemory(Curves, sizeof(Curves)); if (nLocation == 1 || nLocation == 3) @@ -1175,17 +1217,20 @@ LCMSBOOL ReadSetOfCurves(LPLCMSICCPROFIL for (i=0; i < nCurves; i++) { Curves[i] = ReadCurve(Icc); - if (Curves[i] == NULL) return FALSE; + if (Curves[i] == NULL) goto free_out; SkipAlignment(Icc); } NewLUT = cmsAllocLinearTable(NewLUT, Curves, nLocation); - + + ret = TRUE; + +free_out: for (i=0; i < nCurves; i++) cmsFreeGamma(Curves[i]); - return TRUE; + return ret; } @@ -1208,6 +1253,13 @@ LCMSBOOL ReadLUT_A2B(LPLCMSICCPROFILE Ic NewLUT -> InputChan = LUT16.inputChan; NewLUT -> OutputChan = LUT16.outputChan; + // Validate the NewLUT here to avoid excessive number of channels + // (leading to stack-based buffer overflow in ReadSetOfCurves). + // Needs revalidation after table size is filled in. + if (!validateNewLUT(NewLUT)) { + return FALSE; + } + AdjustEndianess32((LPBYTE) &LUT16.offsetB); AdjustEndianess32((LPBYTE) &LUT16.offsetMat); AdjustEndianess32((LPBYTE) &LUT16.offsetM); @@ -1267,6 +1319,13 @@ LCMSBOOL ReadLUT_B2A(LPLCMSICCPROFILE Ic NewLUT -> InputChan = LUT16.inputChan; NewLUT -> OutputChan = LUT16.outputChan; + // Validate the NewLUT here to avoid excessive number of channels + // (leading to stack-based buffer overflow in ReadSetOfCurves). + // Needs revalidation after table size is filled in. + if (!validateNewLUT(NewLUT)) { + return FALSE; + } + AdjustEndianess32((LPBYTE) &LUT16.offsetB); AdjustEndianess32((LPBYTE) &LUT16.offsetMat); AdjustEndianess32((LPBYTE) &LUT16.offsetM); @@ -1415,6 +1474,7 @@ int ReadEmbeddedTextTag(LPLCMSICCPROFILE BaseType = ReadBase(Icc); + // Looks broken: size could be 0, or essentially < sizeof(icTagBase) here. size -= sizeof(icTagBase); switch (BaseType) { @@ -1557,6 +1617,8 @@ int ReadEmbeddedTextTag(LPLCMSICCPROFILE for (i=0; i < Offset; i++) { char Discard; + // No return checking; could lead to large loop in + // combination with int oflow above computing Offset. Icc ->Read(&Discard, 1, 1, Icc); } @@ -1572,6 +1634,7 @@ int ReadEmbeddedTextTag(LPLCMSICCPROFILE AdjustEndianessArray16((LPWORD) wchar, Len / 2); wchar[Len / 2] = L'\0'; + // Failure to null terminate "Name". i = wcstombs(Name, wchar, size_max ); if (i == ((size_t) -1)) { @@ -1941,6 +2004,8 @@ int cmsReadICCnamedColorList(cmsHTRANSFO char Root[33]; ZeroMemory(Colorant, sizeof(WORD) * MAXCHANNELS); + // No return value checking; could cause trouble with + // large count. Icc -> Read(Root, 1, 32, Icc); Icc -> Read(PCS, 3, sizeof(WORD), Icc); @@ -1974,7 +2039,8 @@ int cmsReadICCnamedColorList(cmsHTRANSFO LPcmsNAMEDCOLORLIST LCMSEXPORT cmsReadColorantTable(cmsHPROFILE hProfile, icTagSignature sig) { - icInt32Number n, Count, i; + icInt32Number n; + icUInt32Number Count, i; size_t offset; icTagTypeSignature BaseType; LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile; @@ -2315,6 +2381,9 @@ LPcmsSEQ LCMSEXPORT cmsReadProfileSequen Icc ->Read(&Count, sizeof(icUInt32Number), 1, Icc); AdjustEndianess32((LPBYTE) &Count); + if (Count > 1000) { + return NULL; + } size = sizeof(int) + Count * sizeof(cmsPSEQDESC); OutSeq = (LPcmsSEQ) _cmsMalloc(size); if (OutSeq == NULL) return NULL; @@ -2495,7 +2564,7 @@ cmsHPROFILE LCMSEXPORT cmsOpenProfileFro NewIcc = _cmsCreateProfileFromFilePlaceholder(lpFileName); if (!NewIcc) return NULL; - if (!ReadHeader(NewIcc, FALSE)) return NULL; + if (!ReadHeader(NewIcc, FALSE, 0)) return NULL; ReadCriticalTags(NewIcc); @@ -2515,7 +2584,7 @@ cmsHPROFILE LCMSEXPORT cmsOpenProfileFro NewIcc = _cmsCreateProfileFromMemPlaceholder(MemPtr, dwSize); if (!NewIcc) return NULL; - if (!ReadHeader(NewIcc, TRUE)) return NULL; + if (!ReadHeader(NewIcc, TRUE, dwSize)) return NULL; ReadCriticalTags(NewIcc); diff -uprN lcms-1.17/src/cmslut.c lcms-1.17fixed/src/cmslut.c --- lcms-1.17/src/cmslut.c 2007-07-27 12:00:02.000000000 +0200 +++ lcms-1.17fixed/src/cmslut.c 2009-02-24 01:07:47.000000000 +0100 @@ -192,12 +192,14 @@ LPLUT LCMSEXPORT cmsAlloc3DGrid(LPLUT Ne NewLUT -> InputChan = inputChan; NewLUT -> OutputChan = outputChan; + if (!validateNewLUT(NewLUT)) { + return NULL; + } + nTabSize = NewLUT -> OutputChan * UIpow(NewLUT->cLutPoints, + NewLUT->InputChan); - nTabSize = (NewLUT -> OutputChan * UIpow(NewLUT->cLutPoints, - NewLUT->InputChan) - * sizeof(WORD)); - - NewLUT -> T = (LPWORD) _cmsMalloc(nTabSize); + NewLUT -> T = (LPWORD) _cmsCalloc(sizeof(WORD), nTabSize); + nTabSize *= sizeof(WORD); if (NewLUT -> T == NULL) return NULL; ZeroMemory(NewLUT -> T, nTabSize);