@@ -48,11 +48,10 @@ class SgiInput final : public ImageInput {
4848 // Return true if ok, false if there was a read error.
4949 bool read_offset_tables ();
5050
51- // read channel scanline data from file, uncompress it and save the data to
52- // 'out' buffer; 'out' should be allocate before call to this method.
53- // Return true if ok, false if there was a read error.
51+ // read channel scanline data from file, uncompress it and save the data
52+ // to 'outbuf' buffer. Return true if ok, false if there was a read error.
5453 bool uncompress_rle_channel (int scanline_off, int scanline_len,
55- unsigned char * out );
54+ span< unsigned char > outbf );
5655};
5756
5857
@@ -159,6 +158,12 @@ SgiInput::open(const std::string& name, ImageSpec& spec)
159158 m_spec = ImageSpec (m_sgi_header.xsize , height, nchannels,
160159 m_sgi_header.bpc == 1 ? TypeDesc::UINT8
161160 : TypeDesc::UINT16);
161+
162+ if (!check_open (m_spec, { 0 , 65535 , 0 , 65535 , 0 , 1 , 0 , 4 })) {
163+ close ();
164+ return false ;
165+ }
166+
162167 if (Strutil::safe_strlen (m_sgi_header.imagename ,
163168 sizeof (m_sgi_header.imagename )))
164169 m_spec.attribute (" ImageDescription" , m_sgi_header.imagename );
@@ -198,8 +203,9 @@ SgiInput::read_native_scanline(int subimage, int miplevel, int y, int /*z*/,
198203 ptrdiff_t scanline_offset = start_tab[off];
199204 ptrdiff_t scanline_length = length_tab[off];
200205 channeldata[c].resize (m_spec.width * bpc);
201- uncompress_rle_channel (scanline_offset, scanline_length,
202- &(channeldata[c][0 ]));
206+ if (!uncompress_rle_channel (scanline_offset, scanline_length,
207+ make_span (channeldata[c])))
208+ return false ;
203209 }
204210 } else {
205211 // non-RLE case -- just read directly into our channel data
@@ -240,16 +246,20 @@ SgiInput::read_native_scanline(int subimage, int miplevel, int y, int /*z*/,
240246
241247bool
242248SgiInput::uncompress_rle_channel (int scanline_off, int scanline_len,
243- unsigned char * out )
249+ span< unsigned char > outbuf )
244250{
245251 int bpc = m_sgi_header.bpc ;
246- std::unique_ptr<unsigned char []> rle_scanline (
252+ std::unique_ptr<unsigned char []> rle_scanline_alloc (
247253 new unsigned char [scanline_len]);
254+ auto rle_scanline = make_span (rle_scanline_alloc.get (), scanline_len);
248255 ioseek (scanline_off);
249- if (!ioread (& rle_scanline[ 0 ] , 1 , scanline_len))
256+ if (!ioread (rle_scanline. data () , 1 , scanline_len))
250257 return false ;
258+ OIIO_CONTRACT_ASSERT (outbuf.size ()
259+ >= size_t (m_spec.width * m_sgi_header.bpc ));
251260 int limit = m_spec.width ;
252261 int i = 0 ;
262+ int iout = 0 ;
253263 if (bpc == 1 ) {
254264 // 1 bit per channel
255265 while (i < scanline_len) {
@@ -262,17 +272,23 @@ SgiInput::uncompress_rle_channel(int scanline_off, int scanline_len,
262272 // If the high bit is set, we just copy the next 'count' values
263273 if (value & 0x80 ) {
264274 while (count--) {
265- OIIO_DASSERT (i < scanline_len && limit > 0 );
266- *(out++) = rle_scanline[i++];
275+ if (i >= scanline_len || limit <= 0 ) {
276+ errorfmt (" Corrupt RLE data" );
277+ return false ;
278+ }
279+ outbuf[iout++] = rle_scanline[i++];
267280 --limit;
268281 }
269282 }
270283 // If the high bit is zero, we copy the NEXT value, count times
271284 else {
272285 value = rle_scanline[i++];
273286 while (count--) {
274- OIIO_DASSERT (limit > 0 );
275- *(out++) = value;
287+ if (limit <= 0 ) {
288+ errorfmt (" Corrupt RLE data" );
289+ return false ;
290+ }
291+ outbuf[iout++] = value;
276292 --limit;
277293 }
278294 }
@@ -290,18 +306,24 @@ SgiInput::uncompress_rle_channel(int scanline_off, int scanline_len,
290306 // If the high bit is set, we just copy the next 'count' values
291307 if (value & 0x80 ) {
292308 while (count--) {
293- OIIO_DASSERT (i + 1 < scanline_len && limit > 0 );
294- *(out++) = rle_scanline[i++];
295- *(out++) = rle_scanline[i++];
309+ if ((i + 1 ) >= scanline_len || limit <= 0 ) {
310+ errorfmt (" Corrupt RLE data" );
311+ return false ;
312+ }
313+ outbuf[iout++] = rle_scanline[i++];
314+ outbuf[iout++] = rle_scanline[i++];
296315 --limit;
297316 }
298317 }
299318 // If the high bit is zero, we copy the NEXT value, count times
300319 else {
301320 while (count--) {
302- OIIO_DASSERT (limit > 0 );
303- *(out++) = rle_scanline[i];
304- *(out++) = rle_scanline[i + 1 ];
321+ if (limit <= 0 ) {
322+ errorfmt (" Corrupt RLE data" );
323+ return false ;
324+ }
325+ outbuf[iout++] = rle_scanline[i];
326+ outbuf[iout++] = rle_scanline[i + 1 ];
305327 --limit;
306328 }
307329 i += 2 ;
@@ -363,6 +385,23 @@ SgiInput::read_header()
363385 swap_endian (&m_sgi_header.pixmax );
364386 swap_endian (&m_sgi_header.colormap );
365387 }
388+
389+ if (m_sgi_header.magic != sgi_pvt::SGI_MAGIC) {
390+ errorfmt (" \" {}\" is not a SGI file, magic number doesn't match" ,
391+ m_filename);
392+ return false ;
393+ }
394+
395+ // Corruption checks
396+ if (m_sgi_header.storage < sgi_pvt::VERBATIM
397+ || m_sgi_header.storage > sgi_pvt::RLE //
398+ || m_sgi_header.bpc < 1 || m_sgi_header.bpc > 2
399+ || m_sgi_header.dimension > sgi_pvt::MULTI_SCANLINE_MULTI_CHANNEL
400+ || m_sgi_header.dimension < sgi_pvt::ONE_SCANLINE_ONE_CHANNEL) {
401+ errorfmt (" Corrupt SGI header" );
402+ return false ;
403+ }
404+
366405 return true ;
367406}
368407
0 commit comments