diff --git a/src/targa.imageio/targainput.cpp b/src/targa.imageio/targainput.cpp index b168508374..96104c6e1b 100644 --- a/src/targa.imageio/targainput.cpp +++ b/src/targa.imageio/targainput.cpp @@ -254,6 +254,34 @@ TGAInput::open(const std::string& name, ImageSpec& newspec) if (m_tga.type >= TYPE_PALETTED_RLE) m_spec.attribute("compression", "rle"); + // The width/height/bpp fields are not cross-checked against how much + // pixel data the file actually contains, so a corrupt header can claim + // an arbitrarily large image (e.g. thousands of pixels square) backed + // by only a few bytes of real data. Reject implausible claims before + // committing to a potentially huge allocation in readimg(). Compare + // against the *on-disk* pixel size (palette/16-bit storage is smaller + // per pixel than the decoded, unpacked ImageSpec) -- and RLE can expand + // at most 128x (a 1-byte run-length count can encode up to 128 output + // pixels from very little input) -- so give a generous bound based on + // how much data remains in the file. + { + int bytespp = (m_tga.bpp == 15) ? 2 : (m_tga.bpp / 8); + uint64_t raw_pixel_bytes = uint64_t(m_tga.width) * uint64_t(m_tga.height) + * uint64_t(bytespp); + uint64_t filesize = uint64_t(ioproxy()->size()); + uint64_t pos = uint64_t(iotell()); + uint64_t avail = filesize > pos ? filesize - pos : 0; + uint64_t max_plausible_bytes = (m_tga.type >= TYPE_PALETTED_RLE) + ? avail * 128 + : avail; + if (raw_pixel_bytes > max_plausible_bytes) { + errorfmt( + "TGA header claims image size {} bytes, implausible for {} bytes of remaining file data", + raw_pixel_bytes, avail); + return false; + } + } + /*std::cerr << "[tga] " << m_tga.width << "x" << m_tga.height << "@" << (int)m_tga.bpp << " (" << m_spec.nchannels << ") type " << (int)m_tga.type << "\n";*/ diff --git a/testsuite/targa/ref/out.txt b/testsuite/targa/ref/out.txt index c303fe1b1a..d7b8d03467 100644 --- a/testsuite/targa/ref/out.txt +++ b/testsuite/targa/ref/out.txt @@ -187,8 +187,7 @@ Reading ../oiio-images/targa/round_grill.tga Comparing "../oiio-images/targa/round_grill.tga" and "round_grill.tga" PASS Converting src/crash1.tga to crash1.exr -iconvert ERROR copying "src/crash1.tga" to "crash1.exr" : - Read error: hit end of file in targa reader +iconvert ERROR: TGA header claims image size 1506428560 bytes, implausible for 1886 bytes of remaining file data oiiotool ERROR: read : "src/crash2.tga": Palette image with no palette Full command line was: > oiiotool --oiioattrib try_all_readers 0 src/crash2.tga -o crash2.exr @@ -204,9 +203,7 @@ Full command line was: oiiotool ERROR: read : "src/crash1708.tga": Too big a color palette (382) for 8 bpp, assume corruption Full command line was: > oiiotool --oiioattrib try_all_readers 0 src/crash1708.tga -o crash1708.exr -oiiotool ERROR: read : "src/crash3952.tga": Uncompressed image size 15231.5 MB exceeds the 1024 MB limit. -Image claimed to be 60927x65535, 4-channel uint8. Possible corrupt input? -If this is a valid file, raise the OIIO attribute "limits:imagesize_MB". +oiiotool ERROR: read : "src/crash3952.tga": TGA header claims image size 15971403780 bytes, implausible for 3 bytes of remaining file data Full command line was: > oiiotool --oiioattrib limits:imagesize_MB 1024 --oiioattrib try_all_readers 0 src/crash3952.tga -o crash3952.exr oiiotool ERROR: read : "src/crash-20250423.tga": Corrupt palette index