From 09452b0964d7ccf1b370a0b07973acf810959139 Mon Sep 17 00:00:00 2001 From: Aljo Joby Date: Fri, 14 Aug 2026 21:03:38 +0530 Subject: [PATCH] rgb: reject RLE start offsets that underflow the raster data The start table is stored as file offsets. We subtract the header+table size to get an index into the remaining data. If the file offset is smaller than that, the subtract wraps and the later start+length check can wrap too. Drop the file instead of walking off the buffer. --- src/imageformats/rgb.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/imageformats/rgb.cpp b/src/imageformats/rgb.cpp index 1052fac..17bda89 100644 --- a/src/imageformats/rgb.cpp +++ b/src/imageformats/rgb.cpp @@ -314,6 +314,8 @@ bool SGIImagePrivate::readImage(QImage &img) _numrows = _ysize * _zsize; if (_rle) { + // start table holds file offsets; raster data follows header + both tables + const quint32 dataOff = 512 + _numrows * 2 * sizeof(quint32); uint l; _starttab = new (std::nothrow) quint32[_numrows]; if (_starttab == nullptr) { @@ -321,7 +323,10 @@ bool SGIImagePrivate::readImage(QImage &img) } for (l = 0; !_stream.atEnd() && l < _numrows; l++) { _stream >> _starttab[l]; - _starttab[l] -= 512 + _numrows * 2 * sizeof(quint32); + if (_starttab[l] < dataOff) { + return false; + } + _starttab[l] -= dataOff; if (_stream.status() != QDataStream::Ok) { return false; } @@ -353,9 +358,10 @@ bool SGIImagePrivate::readImage(QImage &img) // sanity check if (_rle) { + const uint dataSize = uint(_data.size()); for (uint o = 0; o < _numrows; o++) { - // don't change to greater-or-equal! - if (_starttab[o] + _lengthtab[o] > (uint)_data.size()) { + // don't add start+length: uint32 wrap would pass a corrupt file + if (_starttab[o] > dataSize || _lengthtab[o] > dataSize - _starttab[o]) { // qCDebug(LOG_RGBPLUGIN) << "image corrupt (sanity check failed)"; return false; }