diff --git a/src/zfile.imageio/zfile.cpp b/src/zfile.imageio/zfile.cpp index 56273a9197..7bbf0c6843 100644 --- a/src/zfile.imageio/zfile.cpp +++ b/src/zfile.imageio/zfile.cpp @@ -173,7 +173,10 @@ ZfileInput::open(const std::string& name, ImageSpec& newspec) ZfileHeader header; static_assert(sizeof(header) == 136, "header size does not match"); - gzread(m_gz, &header, sizeof(header)); + if (gzread(m_gz, &header, sizeof(header)) != int(sizeof(header))) { + errorfmt("Not a valid Zfile (truncated header)"); + return false; + } if (header.magic != zfile_magic && header.magic != zfile_magic_endian) { errorfmt("Not a valid Zfile"); @@ -245,7 +248,12 @@ ZfileInput::read_native_scanline(int subimage, int miplevel, int y, int /*z*/, } while (m_next_scanline <= y) { // Keep reading until we're read the scanline we really need - gzread(m_gz, data, m_spec.width * sizeof(float)); + int want = int(m_spec.width * sizeof(float)); + if (gzread(m_gz, data, want) != want) { + errorfmt("Error reading zfile scanline {} (corrupt or truncated)", + m_next_scanline); + return false; + } ++m_next_scanline; } if (m_swab) diff --git a/testsuite/zfile/ref/out-macarm.txt b/testsuite/zfile/ref/out-macarm.txt index c49b293203..6a3b857dc5 100644 --- a/testsuite/zfile/ref/out-macarm.txt +++ b/testsuite/zfile/ref/out-macarm.txt @@ -13,5 +13,11 @@ out.zfile : 64 x 64, 1 channel, float zfile Stats FiniteCount: 4096 Constant: No Monochrome: Yes +oiiotool ERROR: read : "src/bomb-32767.zfile": zfile header claims a 4095 MB image from a 136 byte file; probably a corrupt or malicious header +Full command line was: +> oiiotool -nostderr -info src/bomb-32767.zfile +oiiotool ERROR: read : "src/truncated.zfile": Error reading zfile scanline 0 (corrupt or truncated) +Full command line was: +> oiiotool -nostderr src/truncated.zfile -o truncated.exr Comparing "out.zfile" and "ref/out.zfile" PASS diff --git a/testsuite/zfile/ref/out.txt b/testsuite/zfile/ref/out.txt index 24d5734cc4..9bb716b246 100644 --- a/testsuite/zfile/ref/out.txt +++ b/testsuite/zfile/ref/out.txt @@ -13,5 +13,11 @@ out.zfile : 64 x 64, 1 channel, float zfile Stats FiniteCount: 4096 Constant: No Monochrome: Yes +oiiotool ERROR: read : "src/bomb-32767.zfile": zfile header claims a 4095 MB image from a 136 byte file; probably a corrupt or malicious header +Full command line was: +> oiiotool -nostderr -info src/bomb-32767.zfile +oiiotool ERROR: read : "src/truncated.zfile": Error reading zfile scanline 0 (corrupt or truncated) +Full command line was: +> oiiotool -nostderr src/truncated.zfile -o truncated.exr Comparing "out.zfile" and "ref/out.zfile" PASS diff --git a/testsuite/zfile/run.py b/testsuite/zfile/run.py index ec0da0dc05..db4fc92fe9 100755 --- a/testsuite/zfile/run.py +++ b/testsuite/zfile/run.py @@ -9,4 +9,11 @@ command += oiiotool ("-pattern fill:topleft=0.1:topright=0.5:bottomleft=1.0:bottomright=0.3 64x64 1 -chnames Z -d float -o out.zfile") command += info_command ("out.zfile", extraargs="-stats") +# A 136-byte header declaring a 32767x32767 (~4 GB) image: the +# compression-ratio guard must reject it before the caller allocates. +command += oiiotool ("-nostderr -info src/bomb-32767.zfile", failureok=True) +# Truncated gzip pixel data: the scanline read must hard-error rather than +# return an uninitialized buffer. +command += oiiotool ("-nostderr src/truncated.zfile -o truncated.exr", failureok=True) + outputs = [ "out.zfile", "out.txt" ] diff --git a/testsuite/zfile/src/bomb-32767.zfile b/testsuite/zfile/src/bomb-32767.zfile new file mode 100644 index 0000000000..b45e2e0b6c Binary files /dev/null and b/testsuite/zfile/src/bomb-32767.zfile differ diff --git a/testsuite/zfile/src/truncated.zfile b/testsuite/zfile/src/truncated.zfile new file mode 100644 index 0000000000..459ce159c0 Binary files /dev/null and b/testsuite/zfile/src/truncated.zfile differ