File lcms-bnc479606.patch of Package lcms
--- lcms-1.17/include/lcms.h
+++ lcms-1.18/include/lcms.h
@@ -1415,6 +1415,14 @@
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)
{
@@ -2027,6 +2035,10 @@
// Build a tone curve for K->K' if possible (only works on CMYK)
LPGAMMATABLE _cmsBuildKToneCurve(cmsHTRANSFORM hCMYK2CMYK, int nPoints);
+// Validates a LUT
+LCMSBOOL cdecl _cmsValidateLUT(LPLUT NewLUT);
+
+
// These are two VITAL macros, from converting between 8 and 16 bit
// representation.
--- lcms-1.17/src/cmsgamma.c
+++ lcms-1.18/src/cmsgamma.c
@@ -114,7 +114,7 @@
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;
}
--- lcms-1.17/src/cmsio0.c
+++ lcms-1.18/src/cmsio0.c
@@ -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 @@
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){
--- lcms-1.17/src/cmsio1.c
+++ lcms-1.18/src/cmsio1.c
@@ -261,11 +261,14 @@
// 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;
@@ -287,6 +290,10 @@
if (Header.magic != icMagicNumber) goto ErrorCleanup;
+ if (dwSize && dwSize != Header.size) {
+ goto ErrorCleanup;
+ }
+
if (Icc ->Read(&TagCount, sizeof(icInt32Number), 1, Icc) != 1)
goto ErrorCleanup;
@@ -321,7 +328,7 @@
// 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;
@@ -338,8 +345,9 @@
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;
@@ -494,9 +502,9 @@
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 (!_cmsValidateLUT(NewLUT)) {
+ return FALSE;
+ }
AdjustEndianess32((LPBYTE) &LUT8.e00);
AdjustEndianess32((LPBYTE) &LUT8.e01);
@@ -571,7 +579,7 @@
if (nTabSize > 0) {
- PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * nTabSize);
+ PtrW = (LPWORD) _cmsCalloc(sizeof(WORD), nTabSize);
if (PtrW == NULL) return FALSE;
Temp = (LPBYTE) _cmsMalloc(nTabSize);
@@ -662,6 +670,15 @@
// some profiles does claim to do that. Poor lcms will try
// to detect such condition and fix up "on the fly".
+ switch (sig) {
+
+ case icSigBToA0Tag:
+ case icSigBToA1Tag:
+ case icSigBToA2Tag:
+ case icSigGamutTag:
+ case icSigPreview0Tag:
+ case icSigPreview1Tag:
+ case icSigPreview2Tag:
{
LPWORD WhiteLab, ExpectedWhite;
WORD WhiteFixed[MAXCHANNELS], WhiteUnfixed[MAXCHANNELS];
@@ -701,7 +718,10 @@
}
}
+ break;
+ default:;
+ }
}
return TRUE;
@@ -736,6 +756,9 @@
NewLUT -> InputEntries = LUT16.inputEnt;
NewLUT -> OutputEntries = LUT16.outputEnt;
+ if (!_cmsValidateLUT(NewLUT)) {
+ return FALSE;
+ }
// Matrix handling
@@ -798,11 +821,9 @@
NewLUT->InputChan));
if (nTabSize > 0) {
- PtrW = (LPWORD) _cmsMalloc(sizeof(WORD) * nTabSize);
- if (PtrW == NULL) {
- _cmsFree(PtrW);
+ PtrW = (LPWORD) _cmsCalloc(sizeof(WORD), nTabSize);
+ if (PtrW == NULL)
return FALSE;
- }
NewLUT -> T = PtrW;
NewLUT -> Tsize = (unsigned int) (nTabSize * sizeof(WORD));
@@ -1108,15 +1129,24 @@
static
LCMSBOOL ReadCLUT(LPLCMSICCPROFILE Icc, size_t Offset, LPLUT NewLUT)
{
-
+ unsigned int j;
icCLutStruct CLUT;
if (Icc -> Seek(Icc, Offset)) return FALSE;
if (Icc ->Read(&CLUT, sizeof(icCLutStruct), 1, Icc) != 1) return FALSE;
- cmsAlloc3DGrid(NewLUT, CLUT.gridPoints[0], NewLUT ->InputChan,
- NewLUT ->OutputChan);
+ for (j=1; j < NewLUT ->InputChan; j++) {
+ if (CLUT.gridPoints[0] != CLUT.gridPoints[j]) {
+ cmsSignalError(LCMS_ERRC_ABORTED, "CLUT with different granulatity is currently unsupported.");
+ return FALSE;
+ }
+
+
+ }
+
+ if (cmsAlloc3DGrid(NewLUT, CLUT.gridPoints[0], NewLUT ->InputChan,
+ NewLUT ->OutputChan) == NULL) return FALSE;
// Precission can be 1 or 2 bytes
@@ -1173,10 +1203,11 @@
else
nCurves = NewLUT ->OutputChan;
+ ZeroMemory(Curves, sizeof(Curves));
for (i=0; i < nCurves; i++) {
Curves[i] = ReadCurve(Icc);
- if (Curves[i] == NULL) return FALSE;
+ if (Curves[i] == NULL) goto Error;
SkipAlignment(Icc);
}
@@ -1188,6 +1219,16 @@
return TRUE;
+Error:
+ for (i=0; i < nCurves; i++) {
+
+ if (Curves[i])
+ cmsFreeGamma(Curves[i]);
+ }
+
+ return FALSE;
+
+
}
// V4 stuff. LutAtoB type
@@ -1209,6 +1250,13 @@
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 (!_cmsValidateLUT(NewLUT)) {
+ return FALSE;
+ }
+
AdjustEndianess32((LPBYTE) &LUT16.offsetB);
AdjustEndianess32((LPBYTE) &LUT16.offsetMat);
AdjustEndianess32((LPBYTE) &LUT16.offsetM);
@@ -1268,6 +1316,13 @@
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 (!_cmsValidateLUT(NewLUT)) {
+ return FALSE;
+ }
+
AdjustEndianess32((LPBYTE) &LUT16.offsetB);
AdjustEndianess32((LPBYTE) &LUT16.offsetMat);
AdjustEndianess32((LPBYTE) &LUT16.offsetM);
@@ -1558,6 +1613,8 @@
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);
}
@@ -1566,7 +1623,7 @@
if (Len < 0) Len = 0;
if (Len > 20*1024) Len = 20 * 1024;
- wchar = (wchar_t*) _cmsMalloc(Len+2);
+ wchar = (wchar_t*) _cmsMalloc(Len*sizeof(wchar_t)+2);
if (!wchar) return -1;
if (Icc ->Read(wchar, 1, Len, Icc) != Len) return -1;
@@ -1942,6 +1999,8 @@
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);
@@ -1975,7 +2034,8 @@
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;
@@ -2316,6 +2376,10 @@
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;
@@ -2496,7 +2560,7 @@
NewIcc = _cmsCreateProfileFromFilePlaceholder(lpFileName);
if (!NewIcc) return NULL;
- if (!ReadHeader(NewIcc, FALSE)) return NULL;
+ if (!ReadHeader(NewIcc, FALSE, 0)) return NULL;
ReadCriticalTags(NewIcc);
@@ -2516,7 +2580,7 @@
NewIcc = _cmsCreateProfileFromMemPlaceholder(MemPtr, dwSize);
if (!NewIcc) return NULL;
- if (!ReadHeader(NewIcc, TRUE)) return NULL;
+ if (!ReadHeader(NewIcc, TRUE, dwSize)) return NULL;
ReadCriticalTags(NewIcc);
--- lcms-1.17/src/cmslut.c
+++ lcms-1.18/src/cmslut.c
@@ -183,6 +183,37 @@
}
+LCMSBOOL _cmsValidateLUT(LPLUT NewLUT)
+{
+ unsigned int calc = 1;
+ unsigned int oldCalc;
+ unsigned int power = NewLUT -> InputChan;
+
+ if (NewLUT -> cLutPoints > 100) return FALSE;
+ if (NewLUT -> InputChan > MAXCHANNELS) return FALSE;
+ if (NewLUT -> OutputChan > MAXCHANNELS) return FALSE;
+
+ if (NewLUT -> cLutPoints == 0) return TRUE;
+
+ for (; power > 0; power--) {
+
+ oldCalc = calc;
+ calc *= NewLUT -> cLutPoints;
+
+ if (calc < oldCalc || calc < NewLUT -> cLutPoints) {
+ return FALSE;
+ }
+ }
+
+ oldCalc = calc;
+ calc *= NewLUT -> OutputChan;
+ if (calc < oldCalc || calc < NewLUT -> OutputChan) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
LPLUT LCMSEXPORT cmsAlloc3DGrid(LPLUT NewLUT, int clutPoints, int inputChan, int outputChan)
{
DWORD nTabSize;
@@ -192,12 +223,15 @@
NewLUT -> InputChan = inputChan;
NewLUT -> OutputChan = outputChan;
+ if (!_cmsValidateLUT(NewLUT)) {
+ return NULL;
+ }
- nTabSize = (NewLUT -> OutputChan * UIpow(NewLUT->cLutPoints,
- NewLUT->InputChan)
- * sizeof(WORD));
+ nTabSize = NewLUT -> OutputChan * UIpow(NewLUT->cLutPoints,
+ NewLUT->InputChan);
- 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);