Cherrypick upstream Little CMS fixes for uninit reads.
Cherrypick a fix [1] and a follow-up fix [2] from upstream.
[1] https://github.com/mm2/Little-CMS/commit/343efbac4db1e509c5027c53dd8c7d27104c796c
[2] https://github.com/mm2/Little-CMS/commit/1c3ccf4724333743dbef6d828bb22fc7776ad1e8
Bug: chromium:1287081
Change-Id: Ie268354178f4ed43794aba5a9061475c7ff46cc6
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/89330
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/third_party/lcms/0034-uninitialized-reads.patch b/third_party/lcms/0034-uninitialized-reads.patch
new file mode 100644
index 0000000..303266e
--- /dev/null
+++ b/third_party/lcms/0034-uninitialized-reads.patch
@@ -0,0 +1,161 @@
+diff --git a/third_party/lcms/src/cmsintrp.c b/third_party/lcms/src/cmsintrp.c
+index 3d9a40530..22de3e550 100644
+--- a/third_party/lcms/src/cmsintrp.c
++++ b/third_party/lcms/src/cmsintrp.c
+@@ -200,8 +200,8 @@ void LinLerp1D(CMSREGISTER const cmsUInt16Number Value[],
+ int val3;
+ const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
+
+- // if last value...
+- if (Value[0] == 0xffff) {
++ // if last value or just one point
++ if (Value[0] == 0xffff || p->Domain[0] == 0) {
+
+ Output[0] = LutTable[p -> Domain[0]];
+ }
+@@ -240,7 +240,7 @@ void LinLerp1Dfloat(const cmsFloat32Number Value[],
+ val2 = fclamp(Value[0]);
+
+ // if last value...
+- if (val2 == 1.0) {
++ if (val2 == 1.0 || p->Domain[0] == 0) {
+ Output[0] = LutTable[p -> Domain[0]];
+ }
+ else
+@@ -274,20 +274,34 @@ void Eval1Input(CMSREGISTER const cmsUInt16Number Input[],
+ cmsUInt32Number OutChan;
+ const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
+
+- v = Input[0] * p16 -> Domain[0];
+- fk = _cmsToFixedDomain(v);
+
+- k0 = FIXED_TO_INT(fk);
+- rk = (cmsUInt16Number) FIXED_REST_TO_INT(fk);
++ // if last value...
++ if (Input[0] == 0xffff || p16->Domain[0] == 0) {
++
++ cmsUInt16Number y0 = LutTable[p16->Domain[0]];
++
++ for (OutChan = 0; OutChan < p16->nOutputs; OutChan++) {
++ Output[OutChan] = y0;
++ }
++ }
++ else
++ {
++
++ v = Input[0] * p16->Domain[0];
++ fk = _cmsToFixedDomain(v);
++
++ k0 = FIXED_TO_INT(fk);
++ rk = (cmsUInt16Number)FIXED_REST_TO_INT(fk);
+
+- k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0);
++ k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0);
+
+- K0 = p16 -> opta[0] * k0;
+- K1 = p16 -> opta[0] * k1;
++ K0 = p16->opta[0] * k0;
++ K1 = p16->opta[0] * k1;
+
+- for (OutChan=0; OutChan < p16->nOutputs; OutChan++) {
++ for (OutChan = 0; OutChan < p16->nOutputs; OutChan++) {
+
+- Output[OutChan] = LinearInterp(rk, LutTable[K0+OutChan], LutTable[K1+OutChan]);
++ Output[OutChan] = LinearInterp(rk, LutTable[K0 + OutChan], LutTable[K1 + OutChan]);
++ }
+ }
+ }
+
+@@ -308,7 +322,7 @@ void Eval1InputFloat(const cmsFloat32Number Value[],
+ val2 = fclamp(Value[0]);
+
+ // if last value...
+- if (val2 == 1.0) {
++ if (val2 == 1.0 || p->Domain[0] == 0) {
+
+ y0 = LutTable[p->Domain[0]];
+
+diff --git a/third_party/lcms/src/cmsio0.c b/third_party/lcms/src/cmsio0.c
+index 743b958df..ff8c464fc 100644
+--- a/third_party/lcms/src/cmsio0.c
++++ b/third_party/lcms/src/cmsio0.c
+@@ -1538,8 +1538,12 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
+ if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return NULL;
+
+ n = _cmsSearchTag(Icc, sig, TRUE);
+- if (n < 0) goto Error; // Not found, return NULL
+-
++ if (n < 0)
++ {
++ // Not found, return NULL
++ _cmsUnlockMutex(Icc->ContextID, Icc->UsrMutex);
++ return NULL;
++ }
+
+ // If the element is already in memory, return the pointer
+ if (Icc -> TagPtrs[n]) {
+diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c
+index 825b11eb1..49207735b 100644
+--- a/third_party/lcms/src/cmstypes.c
++++ b/third_party/lcms/src/cmstypes.c
+@@ -3515,42 +3515,48 @@ void *Type_UcrBg_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm
+ {
+ cmsUcrBg* n = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg));
+ cmsUInt32Number CountUcr, CountBg;
++ cmsInt32Number SignedSizeOfTag = (cmsInt32Number)SizeOfTag;
+ char* ASCIIString;
+
+ *nItems = 0;
+ if (n == NULL) return NULL;
+
+ // First curve is Under color removal
++
++ if (SignedSizeOfTag < sizeof(cmsUInt32Number)) return NULL;
+ if (!_cmsReadUInt32Number(io, &CountUcr)) return NULL;
+- if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
+- SizeOfTag -= sizeof(cmsUInt32Number);
++ SignedSizeOfTag -= sizeof(cmsUInt32Number);
+
+ n ->Ucr = cmsBuildTabulatedToneCurve16(self ->ContextID, CountUcr, NULL);
+ if (n ->Ucr == NULL) return NULL;
+
++ if (SignedSizeOfTag < (cmsInt32Number)CountUcr * sizeof(cmsUInt16Number)) return NULL;
+ if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) return NULL;
+- if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
+- SizeOfTag -= CountUcr * sizeof(cmsUInt16Number);
++
++ SignedSizeOfTag -= CountUcr * sizeof(cmsUInt16Number);
+
+ // Second curve is Black generation
++
++ if (SignedSizeOfTag < sizeof(cmsUInt32Number)) return NULL;
+ if (!_cmsReadUInt32Number(io, &CountBg)) return NULL;
+- if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
+- SizeOfTag -= sizeof(cmsUInt32Number);
++ SignedSizeOfTag -= sizeof(cmsUInt32Number);
+
+ n ->Bg = cmsBuildTabulatedToneCurve16(self ->ContextID, CountBg, NULL);
+ if (n ->Bg == NULL) return NULL;
++
++ if (SignedSizeOfTag < (cmsInt32Number) CountBg * sizeof(cmsUInt16Number)) return NULL;
+ if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) return NULL;
+- if (SizeOfTag < CountBg * sizeof(cmsUInt16Number)) return NULL;
+- SizeOfTag -= CountBg * sizeof(cmsUInt16Number);
+- if (SizeOfTag == UINT_MAX) return NULL;
++ SignedSizeOfTag -= CountBg * sizeof(cmsUInt16Number);
++
++ if (SignedSizeOfTag < 0 || SignedSizeOfTag > 32000) return NULL;
+
+ // Now comes the text. The length is specified by the tag size
+ n ->Desc = cmsMLUalloc(self ->ContextID, 1);
+ if (n ->Desc == NULL) return NULL;
+
+- ASCIIString = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1);
+- if (io ->Read(io, ASCIIString, sizeof(char), SizeOfTag) != SizeOfTag) return NULL;
+- ASCIIString[SizeOfTag] = 0;
++ ASCIIString = (char*) _cmsMalloc(self ->ContextID, SignedSizeOfTag + 1);
++ if (io ->Read(io, ASCIIString, sizeof(char), SignedSizeOfTag) != (cmsUInt32Number) SignedSizeOfTag) return NULL;
++ ASCIIString[SignedSizeOfTag] = 0;
+ cmsMLUsetASCII(n ->Desc, cmsNoLanguage, cmsNoCountry, ASCIIString);
+ _cmsFree(self ->ContextID, ASCIIString);
+
diff --git a/third_party/lcms/README.pdfium b/third_party/lcms/README.pdfium
index 52e4ceb..8a0fafb 100644
--- a/third_party/lcms/README.pdfium
+++ b/third_party/lcms/README.pdfium
@@ -20,3 +20,4 @@
0029-drop-register-keyword.patch: Remove deprecated 'register' keyword.
0030-const-data.patch: Mark many data structures as const.
0033-opt-integer-overflow.patch: Protect against integer overflow.
+0034-uninitialized-reads.patch: Protect against corrupt profiles.
diff --git a/third_party/lcms/src/cmsintrp.c b/third_party/lcms/src/cmsintrp.c
index 3d9a405..22de3e5 100644
--- a/third_party/lcms/src/cmsintrp.c
+++ b/third_party/lcms/src/cmsintrp.c
@@ -200,8 +200,8 @@
int val3;
const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
- // if last value...
- if (Value[0] == 0xffff) {
+ // if last value or just one point
+ if (Value[0] == 0xffff || p->Domain[0] == 0) {
Output[0] = LutTable[p -> Domain[0]];
}
@@ -240,7 +240,7 @@
val2 = fclamp(Value[0]);
// if last value...
- if (val2 == 1.0) {
+ if (val2 == 1.0 || p->Domain[0] == 0) {
Output[0] = LutTable[p -> Domain[0]];
}
else
@@ -274,20 +274,34 @@
cmsUInt32Number OutChan;
const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
- v = Input[0] * p16 -> Domain[0];
- fk = _cmsToFixedDomain(v);
- k0 = FIXED_TO_INT(fk);
- rk = (cmsUInt16Number) FIXED_REST_TO_INT(fk);
+ // if last value...
+ if (Input[0] == 0xffff || p16->Domain[0] == 0) {
- k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0);
+ cmsUInt16Number y0 = LutTable[p16->Domain[0]];
- K0 = p16 -> opta[0] * k0;
- K1 = p16 -> opta[0] * k1;
+ for (OutChan = 0; OutChan < p16->nOutputs; OutChan++) {
+ Output[OutChan] = y0;
+ }
+ }
+ else
+ {
- for (OutChan=0; OutChan < p16->nOutputs; OutChan++) {
+ v = Input[0] * p16->Domain[0];
+ fk = _cmsToFixedDomain(v);
- Output[OutChan] = LinearInterp(rk, LutTable[K0+OutChan], LutTable[K1+OutChan]);
+ k0 = FIXED_TO_INT(fk);
+ rk = (cmsUInt16Number)FIXED_REST_TO_INT(fk);
+
+ k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0);
+
+ K0 = p16->opta[0] * k0;
+ K1 = p16->opta[0] * k1;
+
+ for (OutChan = 0; OutChan < p16->nOutputs; OutChan++) {
+
+ Output[OutChan] = LinearInterp(rk, LutTable[K0 + OutChan], LutTable[K1 + OutChan]);
+ }
}
}
@@ -308,7 +322,7 @@
val2 = fclamp(Value[0]);
// if last value...
- if (val2 == 1.0) {
+ if (val2 == 1.0 || p->Domain[0] == 0) {
y0 = LutTable[p->Domain[0]];
diff --git a/third_party/lcms/src/cmsio0.c b/third_party/lcms/src/cmsio0.c
index 743b958..ff8c464 100644
--- a/third_party/lcms/src/cmsio0.c
+++ b/third_party/lcms/src/cmsio0.c
@@ -1538,8 +1538,12 @@
if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return NULL;
n = _cmsSearchTag(Icc, sig, TRUE);
- if (n < 0) goto Error; // Not found, return NULL
-
+ if (n < 0)
+ {
+ // Not found, return NULL
+ _cmsUnlockMutex(Icc->ContextID, Icc->UsrMutex);
+ return NULL;
+ }
// If the element is already in memory, return the pointer
if (Icc -> TagPtrs[n]) {
diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c
index 825b11e..4920773 100644
--- a/third_party/lcms/src/cmstypes.c
+++ b/third_party/lcms/src/cmstypes.c
@@ -3515,42 +3515,48 @@
{
cmsUcrBg* n = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg));
cmsUInt32Number CountUcr, CountBg;
+ cmsInt32Number SignedSizeOfTag = (cmsInt32Number)SizeOfTag;
char* ASCIIString;
*nItems = 0;
if (n == NULL) return NULL;
// First curve is Under color removal
+
+ if (SignedSizeOfTag < sizeof(cmsUInt32Number)) return NULL;
if (!_cmsReadUInt32Number(io, &CountUcr)) return NULL;
- if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
- SizeOfTag -= sizeof(cmsUInt32Number);
+ SignedSizeOfTag -= sizeof(cmsUInt32Number);
n ->Ucr = cmsBuildTabulatedToneCurve16(self ->ContextID, CountUcr, NULL);
if (n ->Ucr == NULL) return NULL;
+ if (SignedSizeOfTag < (cmsInt32Number)CountUcr * sizeof(cmsUInt16Number)) return NULL;
if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) return NULL;
- if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
- SizeOfTag -= CountUcr * sizeof(cmsUInt16Number);
+
+ SignedSizeOfTag -= CountUcr * sizeof(cmsUInt16Number);
// Second curve is Black generation
+
+ if (SignedSizeOfTag < sizeof(cmsUInt32Number)) return NULL;
if (!_cmsReadUInt32Number(io, &CountBg)) return NULL;
- if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
- SizeOfTag -= sizeof(cmsUInt32Number);
+ SignedSizeOfTag -= sizeof(cmsUInt32Number);
n ->Bg = cmsBuildTabulatedToneCurve16(self ->ContextID, CountBg, NULL);
if (n ->Bg == NULL) return NULL;
+
+ if (SignedSizeOfTag < (cmsInt32Number) CountBg * sizeof(cmsUInt16Number)) return NULL;
if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) return NULL;
- if (SizeOfTag < CountBg * sizeof(cmsUInt16Number)) return NULL;
- SizeOfTag -= CountBg * sizeof(cmsUInt16Number);
- if (SizeOfTag == UINT_MAX) return NULL;
+ SignedSizeOfTag -= CountBg * sizeof(cmsUInt16Number);
+
+ if (SignedSizeOfTag < 0 || SignedSizeOfTag > 32000) return NULL;
// Now comes the text. The length is specified by the tag size
n ->Desc = cmsMLUalloc(self ->ContextID, 1);
if (n ->Desc == NULL) return NULL;
- ASCIIString = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1);
- if (io ->Read(io, ASCIIString, sizeof(char), SizeOfTag) != SizeOfTag) return NULL;
- ASCIIString[SizeOfTag] = 0;
+ ASCIIString = (char*) _cmsMalloc(self ->ContextID, SignedSizeOfTag + 1);
+ if (io ->Read(io, ASCIIString, sizeof(char), SignedSizeOfTag) != (cmsUInt32Number) SignedSizeOfTag) return NULL;
+ ASCIIString[SignedSizeOfTag] = 0;
cmsMLUsetASCII(n ->Desc, cmsNoLanguage, cmsNoCountry, ASCIIString);
_cmsFree(self ->ContextID, ASCIIString);