1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 15:53:03 +04:00

imgcodecs: fix UBSan load-invalid-value in SunRasterDecoder::readHeader (#29150)

Casting the raw integer fields ras_type and maptype directly to their
respective enum types (SunRasType / SunRasMapType) without a prior range
check is undefined behavior under C++11 §7.2/8 when the stored value falls
outside the enum's valid range.

UBSan reports:
  grfmt_sunras.cpp:72: runtime error: load of value 34077, which is not a
  valid value for type 'SunRasMapType'

Fix: read both fields into plain ints first, validate them against the
declared enumerator bounds, and return false (reject the image) on any
out-of-range value before performing the enum cast.  This is the cheapest
correct approach — two integer comparisons added to a path that was already
doing I/O — and ensures no downstream code ever sees an ill-formed enum
value.

Add test_sunraster.cpp with regression tests covering:
- The exact crash_001 payload (invalid maptype 34077 / 0x851d)
- Invalid ras_type values
- maptype = 2 and UINT_MAX (outside [0,1])
- Truncated header
- A valid 8-bpp grayscale image that must still decode correctly

Signed-off-by: FuzzAnything fuzzanything@gmail.com
This commit is contained in:
example
2026-05-27 09:23:18 +08:00
parent afa6777a0a
commit 39da6f45e4
2 changed files with 152 additions and 2 deletions
+14 -2
View File
@@ -61,10 +61,22 @@ bool SunRasterDecoder::readHeader()
int palSize = (m_bpp > 0 && m_bpp <= 8) ? (3*(1 << m_bpp)) : 0;
m_strm.skip( 4 );
m_encoding = (SunRasType)m_strm.getDWord();
m_maptype = (SunRasMapType)m_strm.getDWord();
// Read as plain integers first; validate before casting to enum types.
// Casting an out-of-range integer directly to an enum with no fixed
// underlying type is undefined behavior (C++11 §7.2/8). Reject invalid
// values early so no downstream code ever touches an ill-formed enum.
const int raw_encoding = (int)m_strm.getDWord();
const int raw_maptype = (int)m_strm.getDWord();
m_maplength = m_strm.getDWord();
if (raw_encoding < RAS_OLD || raw_encoding > RAS_FORMAT_RGB)
return false;
if (raw_maptype < RMT_NONE || raw_maptype > RMT_EQUAL_RGB)
return false;
m_encoding = (SunRasType)raw_encoding;
m_maptype = (SunRasMapType)raw_maptype;
if( m_width > 0 && m_height > 0 &&
(m_bpp == 1 || m_bpp == 8 || m_bpp == 24 || m_bpp == 32) &&
(m_encoding == RAS_OLD || m_encoding == RAS_STANDARD ||