Reject profiles with (some) malformed tag data
If we know how to parse a tag, and it fails to parse, then treat the
profile as invalid. Also remove some overly paranoid/redundant error
checking from the static parse helpers.
Change-Id: Ie6c3fff015b512aafd8e6e49620d913d866bf3af
Reviewed-on: https://skia-review.googlesource.com/110240
Commit-Queue: Mike Klein <mtklein@chromium.org>
Reviewed-by: Mike Klein <mtklein@chromium.org>
diff --git a/src/ICCProfile.c b/src/ICCProfile.c
index e467903..cf0cc5b 100644
--- a/src/ICCProfile.c
+++ b/src/ICCProfile.c
@@ -118,35 +118,23 @@
} XYZ_Layout;
static bool read_tag_xyz(const skcms_ICCTag* tag, float* x, float* y, float* z) {
- const XYZ_Layout* xyzTag = NULL;
- if (tag &&
- tag->type == make_signature('X','Y','Z',' ') &&
- tag->size >= SAFE_SIZEOF(XYZ_Layout)) {
- xyzTag = (const XYZ_Layout*)tag->buf;
- }
-
- if (!xyzTag || !x || !y || !z) {
+ if (tag->type != make_signature('X','Y','Z',' ') || tag->size < SAFE_SIZEOF(XYZ_Layout)) {
return false;
}
+ const XYZ_Layout* xyzTag = (const XYZ_Layout*)tag->buf;
+
*x = read_big_fixed(xyzTag->X);
*y = read_big_fixed(xyzTag->Y);
*z = read_big_fixed(xyzTag->Z);
return true;
}
-static bool read_to_XYZD50(const skcms_ICCProfile* profile, skcms_Matrix3x3* toXYZ) {
- if (!profile || !toXYZ) { return false; }
- skcms_ICCTag rXYZ, gXYZ, bXYZ;
- if (!skcms_GetTagBySignature(profile, make_signature('r', 'X', 'Y', 'Z'), &rXYZ) ||
- !skcms_GetTagBySignature(profile, make_signature('g', 'X', 'Y', 'Z'), &gXYZ) ||
- !skcms_GetTagBySignature(profile, make_signature('b', 'X', 'Y', 'Z'), &bXYZ)) {
- return false;
- }
-
- return read_tag_xyz(&rXYZ, &toXYZ->vals[0][0], &toXYZ->vals[1][0], &toXYZ->vals[2][0]) &&
- read_tag_xyz(&gXYZ, &toXYZ->vals[0][1], &toXYZ->vals[1][1], &toXYZ->vals[2][1]) &&
- read_tag_xyz(&bXYZ, &toXYZ->vals[0][2], &toXYZ->vals[1][2], &toXYZ->vals[2][2]);
+static bool read_to_XYZD50(const skcms_ICCTag* rXYZ, const skcms_ICCTag* gXYZ,
+ const skcms_ICCTag* bXYZ, skcms_Matrix3x3* toXYZ) {
+ return read_tag_xyz(rXYZ, &toXYZ->vals[0][0], &toXYZ->vals[1][0], &toXYZ->vals[2][0]) &&
+ read_tag_xyz(gXYZ, &toXYZ->vals[0][1], &toXYZ->vals[1][1], &toXYZ->vals[2][1]) &&
+ read_tag_xyz(bXYZ, &toXYZ->vals[0][2], &toXYZ->vals[1][2], &toXYZ->vals[2][2]);
}
typedef struct {
@@ -299,7 +287,7 @@
static bool get_transfer_function(const skcms_ICCProfile* profile,
skcms_TransferFunction* transferFunction) {
- if (!profile || !profile->has_trc || !transferFunction) {
+ if (!profile->has_trc) {
return false;
}
@@ -683,22 +671,13 @@
return true;
}
-static bool read_a2b(const skcms_ICCProfile* profile, skcms_A2B* a2b) {
- if (!profile || !a2b) {
- return false;
- }
-
- skcms_ICCTag tag;
- if (!skcms_GetTagBySignature(profile, make_signature('A', '2', 'B', '0'), &tag)) {
- return false;
- }
-
- if (tag.type == make_signature('m', 'f', 't', '1')) {
- return read_tag_mft1(&tag, a2b);
- } else if (tag.type == make_signature('m', 'f', 't', '2')) {
- return read_tag_mft2(&tag, a2b);
- } else if (tag.type == make_signature('m', 'A', 'B', ' ')) {
- return read_tag_mab(&tag, a2b);
+static bool read_a2b(const skcms_ICCTag* tag, skcms_A2B* a2b) {
+ if (tag->type == make_signature('m', 'f', 't', '1')) {
+ return read_tag_mft1(tag, a2b);
+ } else if (tag->type == make_signature('m', 'f', 't', '2')) {
+ return read_tag_mft2(tag, a2b);
+ } else if (tag->type == make_signature('m', 'A', 'B', ' ')) {
+ return read_tag_mab(tag, a2b);
}
return false;
@@ -797,17 +776,39 @@
// Pre-parse commonly used tags.
skcms_ICCTag rTRC, gTRC, bTRC;
- profile->has_trc =
- skcms_GetTagBySignature(profile, make_signature('r', 'T', 'R', 'C'), &rTRC) &&
+ if (skcms_GetTagBySignature(profile, make_signature('r', 'T', 'R', 'C'), &rTRC) &&
skcms_GetTagBySignature(profile, make_signature('g', 'T', 'R', 'C'), &gTRC) &&
- skcms_GetTagBySignature(profile, make_signature('b', 'T', 'R', 'C'), &bTRC) &&
- read_curve(rTRC.buf, rTRC.size, &profile->trc[0], NULL) &&
- read_curve(gTRC.buf, gTRC.size, &profile->trc[1], NULL) &&
- read_curve(bTRC.buf, bTRC.size, &profile->trc[2], NULL);
+ skcms_GetTagBySignature(profile, make_signature('b', 'T', 'R', 'C'), &bTRC)) {
+ if (!read_curve(rTRC.buf, rTRC.size, &profile->trc[0], NULL) ||
+ !read_curve(gTRC.buf, gTRC.size, &profile->trc[1], NULL) ||
+ !read_curve(bTRC.buf, bTRC.size, &profile->trc[2], NULL)) {
+ // Malformed TRC tags
+ return false;
+ }
+ profile->has_trc = true;
+ }
profile->has_tf = get_transfer_function(profile, &profile->tf);
- profile->has_toXYZD50 = read_to_XYZD50 (profile, &profile->toXYZD50);
- profile->has_A2B = read_a2b (profile, &profile->A2B);
+
+ skcms_ICCTag rXYZ, gXYZ, bXYZ;
+ if (skcms_GetTagBySignature(profile, make_signature('r', 'X', 'Y', 'Z'), &rXYZ) &&
+ skcms_GetTagBySignature(profile, make_signature('g', 'X', 'Y', 'Z'), &gXYZ) &&
+ skcms_GetTagBySignature(profile, make_signature('b', 'X', 'Y', 'Z'), &bXYZ)) {
+ if (!read_to_XYZD50(&rXYZ, &gXYZ, &bXYZ, &profile->toXYZD50)) {
+ // Malformed XYZ tags
+ return false;
+ }
+ profile->has_toXYZD50 = true;
+ }
+
+ skcms_ICCTag a2b_tag;
+ if (skcms_GetTagBySignature(profile, make_signature('A', '2', 'B', '0'), &a2b_tag)) {
+ if (!read_a2b(&a2b_tag, &profile->A2B)) {
+ // Malformed A2B tag
+ return false;
+ }
+ profile->has_A2B = true;
+ }
return true;
}
diff --git a/tests.c b/tests.c
index ef20677..b1dce57 100644
--- a/tests.c
+++ b/tests.c
@@ -510,7 +510,6 @@
{ "profiles/color.org/Upper_Right.icc", true, NULL, NULL, NULL, &Upper_Right_A2B },
{ "profiles/misc/Apple_Wide_Color.icc", true, NULL, NULL, NULL, &Apple_Wide_Color_A2B },
{ "profiles/misc/Coated_FOGRA39_CMYK.icc", true, NULL, NULL, NULL, &Coated_FOGRA39_CMYK_A2B },
- { "profiles/misc/ColorGATE_Sihl_PhotoPaper.icc", true, NULL, NULL, NULL, NULL }, // Has kTRC. Broken tag table, and A2B0 fails to parse
{ "profiles/misc/ColorLogic_ISO_Coated_CMYK.icc", true, NULL, NULL, NULL, &ColorLogic_ISO_Coated_CMYK_A2B }, // Has kTRC.
{ "profiles/misc/Japan_Color_2001_Coated.icc", true, NULL, NULL, NULL, &Japan_Color_2001_Coated_A2B },
{ "profiles/misc/Lexmark_X110.icc", true, NULL, NULL, NULL, &Lexmark_X110_A2B },
@@ -562,15 +561,18 @@
// fuzzer generated profiles that found parsing bugs
+ // Bad profiles found inn the wild
+ { "profiles/misc/ColorGATE_Sihl_PhotoPaper.icc", false, NULL, NULL, NULL, NULL }, // Broken tag table, and A2B0 fails to parse
+
// Bad tag table data - these should not parse
{ "profiles/fuzz/last_tag_too_small.icc", false, NULL, NULL, NULL, NULL }, // skia:7592
{ "profiles/fuzz/named_tag_too_small.icc", false, NULL, NULL, NULL, NULL }, // skia:7592
- // These parse but have trouble afterward.
- { "profiles/fuzz/curv_size_overflow.icc", true, NULL, NULL, NULL, NULL }, // skia:7593
- { "profiles/fuzz/truncated_curv_tag.icc", true, NULL, NULL, NULL, NULL }, // oss-fuzz:6103
- { "profiles/fuzz/zero_a.icc", true, NULL, NULL, NULL, NULL }, // oss-fuzz:????
- { "profiles/fuzz/a2b_too_many_input_channels.icc", true, NULL, NULL, NULL, NULL }, // oss-fuzz:6521
+ // Bad tag data - these should not parse
+ { "profiles/fuzz/curv_size_overflow.icc", false, NULL, NULL, NULL, NULL }, // skia:7593
+ { "profiles/fuzz/truncated_curv_tag.icc", false, NULL, NULL, NULL, NULL }, // oss-fuzz:6103
+ { "profiles/fuzz/zero_a.icc", false, NULL, NULL, NULL, NULL }, // oss-fuzz:????
+ { "profiles/fuzz/a2b_too_many_input_channels.icc", false, NULL, NULL, NULL, NULL }, // oss-fuzz:6521
};
static void load_file(const char* filename, void** buf, size_t* len) {