Skip to content

Commit 98c7ce8

Browse files
committed
icc improvements, especially for PSD (4644)
The main thing here is that it turns out that when trying to parse the ICC profiles from Photoshop PSD/PSB files, we weren't storing the attributes in the correct way. (Everything else, we shoved in both the "common" and "composite" imagespec, but we left ICC data out of the composite spec.) While I'm at it, I made two other ICC related changes: * Among the several formats with ICC profiles, we were inconsistent about whether we report errors for corrupt ICC profiles and treat the whole image as broken, or just ignore the errors entirely. Fixed in various places to make a consistent policy of always checking the errors, and reporting/terminating if the "imageinput:strict" global attribute is true, allowing it to just ignore the broken ICC record if that attribute is false. * Found a spot in JPEG handling of ICC where we were dangerously trusting of the sizes of things. Replace a risky memcpy with a safer spancpy that can't overrun the buffer bounds when copying. Signed-off-by: Larry Gritz <[email protected]>
1 parent 280f4c9 commit 98c7ce8

File tree

6 files changed

+281
-23
lines changed

6 files changed

+281
-23
lines changed

src/jpeg.imageio/jpeginput.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -427,16 +427,21 @@ JpgInput::read_icc_profile(j_decompress_ptr cinfo, ImageSpec& spec)
427427
if (m->marker == (JPEG_APP0 + 2)
428428
&& !strcmp((const char*)m->data, "ICC_PROFILE")) {
429429
int seq_no = GETJOCTET(m->data[12]);
430-
memcpy(icc_buf.data() + data_offset[seq_no],
431-
m->data + ICC_HEADER_SIZE, data_length[seq_no]);
430+
if (data_offset[seq_no] + data_length[seq_no] > icc_buf.size()) {
431+
errorfmt("Possible corrupt file, invalid ICC profile\n");
432+
return false;
433+
}
434+
spancpy(make_span(icc_buf), data_offset[seq_no],
435+
make_cspan(m->data + ICC_HEADER_SIZE, data_length[seq_no]),
436+
0, data_length[seq_no]);
432437
}
433438
}
434439
spec.attribute("ICCProfile", TypeDesc(TypeDesc::UINT8, total_length),
435440
icc_buf.data());
436441

437442
std::string errormsg;
438443
bool ok = decode_icc_profile(icc_buf, spec, errormsg);
439-
if (!ok) {
444+
if (!ok && OIIO::get_int_attribute("imageinput:strict")) {
440445
errorfmt("Possible corrupt file, could not decode ICC profile: {}\n",
441446
errormsg);
442447
return false;

src/jpeg2000.imageio/jpeg2000input.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -355,10 +355,10 @@ Jpeg2000Input::open(const std::string& name, ImageSpec& p_spec)
355355
cspan<uint8_t>((const uint8_t*)m_image->icc_profile_buf,
356356
m_image->icc_profile_len),
357357
m_spec, errormsg);
358-
if (!ok) {
359-
// errorfmt("Could not decode ICC profile: {}\n", errormsg);
360-
// return false;
361-
// Nah, just skip an ICC specific error?
358+
if (!ok && OIIO::get_int_attribute("imageinput:strict")) {
359+
errorfmt("Possible corrupt file, could not decode ICC profile: {}\n",
360+
errormsg);
361+
return false;
362362
}
363363
}
364364

src/png.imageio/png_pvt.h

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -250,14 +250,12 @@ read_info(png_structp& sp, png_infop& ip, int& bit_depth, int& color_type,
250250
TypeDesc(TypeDesc::UINT8, profile_length),
251251
profile_data);
252252
std::string errormsg;
253-
bool ok = decode_icc_profile(
254-
cspan<uint8_t>((const uint8_t*)profile_data,
255-
span_size_t(profile_length)),
256-
spec, errormsg);
257-
if (!ok) {
258-
// errorfmt("Could not decode ICC profile: {}\n", errormsg);
259-
// return false;
260-
// Nah, just skip an ICC specific error?
253+
bool ok
254+
= decode_icc_profile(make_cspan(profile_data, profile_length),
255+
spec, errormsg);
256+
if (!ok && OIIO::get_int_attribute("imageinput:strict")) {
257+
errorfmt("Could not decode ICC profile: {}\n", errormsg);
258+
return false;
261259
}
262260
}
263261
}

src/psd.imageio/psdinput.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,8 +1245,15 @@ PSDInput::load_resource_1039(uint32_t length)
12451245
TypeDesc type(TypeDesc::UINT8, length);
12461246
common_attribute("ICCProfile", type, icc_buf.get());
12471247
std::string errormsg;
1248-
decode_icc_profile(cspan<uint8_t>(icc_buf.get(), length), m_common_attribs,
1249-
errormsg);
1248+
bool ok = decode_icc_profile(cspan<uint8_t>(icc_buf.get(), length),
1249+
m_common_attribs, errormsg)
1250+
&& decode_icc_profile(cspan<uint8_t>(icc_buf.get(), length),
1251+
m_composite_attribs, errormsg);
1252+
if (!ok && OIIO::get_int_attribute("imageinput:strict")) {
1253+
errorfmt("Possible corrupt file, could not decode ICC profile: {}\n",
1254+
errormsg);
1255+
return false;
1256+
}
12501257
return true;
12511258
}
12521259

src/tiff.imageio/tiffinput.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,9 @@ class TIFFInput final : public ImageInput {
209209
// Read tags from the current directory of m_tif and fill out spec.
210210
// If read_meta is false, assume that m_spec already contains valid
211211
// metadata and should not be cleared or rewritten.
212-
void readspec(bool read_meta = true);
212+
// Return true if all is fine, false if something really bad happens,
213+
// like we think the file is hopelessly corrupted.
214+
bool readspec(bool read_meta = true);
213215

214216
// Figure out all the photometric-related aspects of the header
215217
void readspec_photometric();
@@ -832,7 +834,8 @@ TIFFInput::seek_subimage(int subimage, int miplevel)
832834
m_next_scanline = 0; // next scanline we'll read
833835
if (subimage == m_subimage || TIFFSetDirectory(m_tif, subimage)) {
834836
m_subimage = subimage;
835-
readspec(read_meta);
837+
if (!readspec(read_meta))
838+
return false;
836839

837840
char emsg[1024];
838841
if (m_use_rgba_interface && !TIFFRGBAImageOK(m_tif, emsg)) {
@@ -931,7 +934,7 @@ TIFFInput::spec_dimensions(int subimage, int miplevel)
931934
#define ICC_PROFILE_ATTR "ICCProfile"
932935

933936

934-
void
937+
bool
935938
TIFFInput::readspec(bool read_meta)
936939
{
937940
uint32_t width = 0, height = 0, depth = 0;
@@ -1201,7 +1204,7 @@ TIFFInput::readspec(bool read_meta)
12011204
// assumed to be identical to what we already have in m_spec,
12021205
// skip everything following.
12031206
if (!read_meta)
1204-
return;
1207+
return true;
12051208

12061209
short resunit = -1;
12071210
TIFFGetField(m_tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
@@ -1239,8 +1242,13 @@ TIFFInput::readspec(bool read_meta)
12391242
m_spec.attribute(ICC_PROFILE_ATTR,
12401243
TypeDesc(TypeDesc::UINT8, icc_datasize), icc_buf);
12411244
std::string errormsg;
1242-
decode_icc_profile(cspan<uint8_t>(icc_buf, icc_datasize), m_spec,
1243-
errormsg);
1245+
bool ok = decode_icc_profile(cspan<uint8_t>(icc_buf, icc_datasize),
1246+
m_spec, errormsg);
1247+
if (!ok && OIIO::get_int_attribute("imageinput:strict")) {
1248+
errorfmt("Possible corrupt file, could not decode ICC profile: {}\n",
1249+
errormsg);
1250+
return false;
1251+
}
12441252
}
12451253

12461254
// Search for an EXIF IFD in the TIFF file, and if found, rummage
@@ -1370,6 +1378,8 @@ TIFFInput::readspec(bool read_meta)
13701378

13711379
if (m_testopenconfig) // open-with-config debugging
13721380
m_spec.attribute("oiio:DebugOpenConfig!", 42);
1381+
1382+
return true;
13731383
}
13741384

13751385

0 commit comments

Comments
 (0)