From 0916deea19ededc53a1a4bbf1c67419bf2b7bc04 Mon Sep 17 00:00:00 2001 From: kalt2212 Date: Thu, 8 Oct 2026 13:15:30 -0700 Subject: [PATCH 1/2] IiqDecoder: bounds-check row in bad-pixel defect handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #965 added a bounds check for `col` in the bad-column path of correctSensorDefects(), but the bad-pixel path (case 129) in the same switch validates `col` and not `row`. An attacker-controlled row value (up to 65535) flows via mBadPixelPositions into transferBadPixelsToMap, which writes mBadPixelMap[(pitch * pos_y) + (pos_x >> 3)] guarded only by asserts — a heap OOB write in release builds. --- src/librawspeed/decoders/IiqDecoder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librawspeed/decoders/IiqDecoder.cpp b/src/librawspeed/decoders/IiqDecoder.cpp index 2bd197307..351c98f98 100644 --- a/src/librawspeed/decoders/IiqDecoder.cpp +++ b/src/librawspeed/decoders/IiqDecoder.cpp @@ -505,8 +505,8 @@ void IiqDecoder::correctSensorDefects(ByteStream data) const { const uint16_t type = data.getU16(); data.skipBytes(2); // Ignore unknown/unused bits. - if (col >= mRaw->dim.x) // Value for col is outside the raw image. - continue; + if (col >= mRaw->dim.x || row >= mRaw->dim.y) + continue; // Defect coordinates are outside the raw image. switch (type) { case 131: // bad column case 137: // bad column From a48105b99ca14ea784836dd236bf3566032d805e Mon Sep 17 00:00:00 2001 From: kalt2212 Date: Thu, 8 Oct 2026 13:25:44 -0700 Subject: [PATCH 2/2] IiqDecoder: move bounds check into handleBadPixel() --- src/librawspeed/decoders/IiqDecoder.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librawspeed/decoders/IiqDecoder.cpp b/src/librawspeed/decoders/IiqDecoder.cpp index 351c98f98..a2d5f0096 100644 --- a/src/librawspeed/decoders/IiqDecoder.cpp +++ b/src/librawspeed/decoders/IiqDecoder.cpp @@ -505,8 +505,8 @@ void IiqDecoder::correctSensorDefects(ByteStream data) const { const uint16_t type = data.getU16(); data.skipBytes(2); // Ignore unknown/unused bits. - if (col >= mRaw->dim.x || row >= mRaw->dim.y) - continue; // Defect coordinates are outside the raw image. + if (col >= mRaw->dim.x) // Value for col is outside the raw image. + continue; switch (type) { case 131: // bad column case 137: // bad column @@ -522,6 +522,8 @@ void IiqDecoder::correctSensorDefects(ByteStream data) const { } void IiqDecoder::handleBadPixel(const uint16_t col, const uint16_t row) const { + if (col >= mRaw->dim.x || row >= mRaw->dim.y) + return; // Defect coordinates are outside the raw image. MutexLocker guard(&mRaw->mBadPixelMutex); mRaw->mBadPixelPositions.insert(mRaw->mBadPixelPositions.end(), (static_cast(row) << 16) + col);