diff --git a/src/gif.imageio/gifinput.cpp b/src/gif.imageio/gifinput.cpp index 8ea1aaf70a..fb38f692ba 100644 --- a/src/gif.imageio/gifinput.cpp +++ b/src/gif.imageio/gifinput.cpp @@ -3,6 +3,7 @@ // https://github.com/AcademySoftwareFoundation/OpenImageIO #include +#include #include #include @@ -203,12 +204,16 @@ GIFInput::read_native_scanline(int subimage, int miplevel, int y, int /*z*/, if (!seek_subimage(subimage, miplevel)) return false; - if (y < 0 || y > m_spec.height || !m_canvas.size()) + if (y < 0 || y >= m_spec.height || m_canvas.empty()) return false; - memcpy(data, - &m_canvas[int64_t(y) * int64_t(m_spec.width) * m_spec.nchannels], - m_spec.width * m_spec.nchannels); + size_t scanline_bytes = m_spec.scanline_bytes(); + size_t offset = size_t(y) * scanline_bytes; + if (scanline_bytes > m_canvas.size() + || offset > m_canvas.size() - scanline_bytes) + return false; + + memcpy(data, m_canvas.data() + offset, scanline_bytes); return true; } @@ -338,8 +343,13 @@ GIFInput::read_subimage_data() if (m_subimage == 0 || m_previous_disposal_method == DISPOSE_BACKGROUND) { // make whole canvas transparent + size_t canvas_pixels = m_spec.image_pixels(); + if (canvas_pixels > std::numeric_limits::max() / size_t(4)) { + errorfmt("GIF image canvas is too large"); + return false; + } m_canvas.clear(); - m_canvas.resize(m_spec.image_pixels() * size_t(4), 0x00); + m_canvas.resize(canvas_pixels * size_t(4), 0x00); } // decode scanline index if image is interlaced @@ -366,10 +376,16 @@ GIFInput::read_subimage_data() fscanline[wx], wx, y, colormap_count); return false; } - int x = window_left + wx; - int64_t idx = m_spec.nchannels - * (int64_t(y) * m_spec.width + x); + int x = window_left + wx; if (0 <= x && x < m_spec.width) { + size_t nchannels = size_t(m_spec.nchannels); + size_t row = size_t(y) * size_t(m_spec.width); + size_t idx = (row + size_t(x)) * nchannels; + if (idx > m_canvas.size() + || nchannels > m_canvas.size() - idx) { + errorfmt("GIF pixel index is outside the canvas"); + return false; + } m_canvas[idx] = colormap[fscanline[wx]].Red; m_canvas[idx + 1] = colormap[fscanline[wx]].Green; m_canvas[idx + 2] = colormap[fscanline[wx]].Blue; diff --git a/testsuite/gif/ref/out.txt b/testsuite/gif/ref/out.txt index 0ed560899a..30ce27631e 100644 --- a/testsuite/gif/ref/out.txt +++ b/testsuite/gif/ref/out.txt @@ -109,3 +109,6 @@ tahoe-tiny.gif : 128 x 96, 4 channel, uint8 gif oiiotool ERROR: read : "src/crash_4163.gif": Wrong record type detected Full command line was: > oiiotool -nostderr -oiioattrib try_all_readers 0 src/crash_4163.gif -o test.exr +oiiotool ERROR: read : "src/gif_idx_overflow_32768x16385_top16384_1x1.gif": GIF image canvas is too large +Full command line was: +> oiiotool --info -oiioattrib try_all_readers 0 src/gif_idx_overflow_32768x16385_top16384_1x1.gif diff --git a/testsuite/gif/run.py b/testsuite/gif/run.py index bf91f9ec4f..6fc4fc5387 100755 --- a/testsuite/gif/run.py +++ b/testsuite/gif/run.py @@ -4,6 +4,8 @@ # SPDX-License-Identifier: Apache-2.0 # https://github.com/AcademySoftwareFoundation/OpenImageIO +redirect = " >> out.txt 2>&1 " + files = ["gif_animation.gif", "gif_oiio_logo_with_alpha.gif", "gif_tahoe.gif", "gif_tahoe_interlaced.gif", "gif_bluedot.gif", "gif_diagonal_interlaced.gif", @@ -18,5 +20,8 @@ # Regression tests command += oiiotool ("-nostderr -oiioattrib try_all_readers 0 src/crash_4163.gif -o test.exr", failureok = True) +command += info_command ("src/gif_idx_overflow_32768x16385_top16384_1x1.gif", + extraargs="-oiioattrib try_all_readers 0", + verbose=False, hash=False, failureok=True) outputs = [ "tahoe-tiny.gif", "out.txt" ] diff --git a/testsuite/gif/src/gif_idx_overflow_32768x16385_top16384_1x1.gif b/testsuite/gif/src/gif_idx_overflow_32768x16385_top16384_1x1.gif new file mode 100644 index 0000000000..22c9a90161 Binary files /dev/null and b/testsuite/gif/src/gif_idx_overflow_32768x16385_top16384_1x1.gif differ