@@ -294,7 +294,7 @@ class PSDInput final : public ImageInput {
294294
295295 void set_type_desc ();
296296 // Setup m_specs and m_channels
297- void setup ();
297+ bool setup ();
298298 void fill_channel_names (ImageSpec& spec, bool transparency);
299299
300300 // Read a row of channel data
@@ -619,9 +619,11 @@ PSDInput::open(const std::string& name, ImageSpec& newspec)
619619 // Set m_type_desc to the appropriate TypeDesc
620620 set_type_desc ();
621621 // Setup ImageSpecs and m_channels
622- setup ();
622+ bool ok = true ;
623+ ok &= setup ();
623624
624- bool ok = seek_subimage (0 , 0 );
625+ if (ok)
626+ ok &= seek_subimage (0 , 0 );
625627 if (ok)
626628 newspec = spec ();
627629 else
@@ -1468,7 +1470,9 @@ PSDInput::load_layers()
14681470 ok &= read_bige<int16_t >(layer_info.layer_count );
14691471 if (layer_info.layer_count < 0 ) {
14701472 m_image_data.transparency = true ;
1471- layer_info.layer_count = -layer_info.layer_count ;
1473+ if (layer_info.layer_count == -32768 )
1474+ return false ; // will overflow when negated
1475+ layer_info.layer_count = -layer_info.layer_count ;
14721476 }
14731477 m_layers.resize (layer_info.layer_count );
14741478 for (int16_t layer_nbr = 0 ; layer_nbr < layer_info.layer_count ;
@@ -1639,6 +1643,7 @@ PSDInput::load_layer_channel(Layer& layer, ChannelInfo& channel_info)
16391643 channel_info.row_pos .resize (height);
16401644 channel_info.row_length = (width * m_header.depth + 7 ) / 8 ;
16411645
1646+ bool ok = true ;
16421647 switch (channel_info.compression ) {
16431648 case Compression_Raw:
16441649 if (height) {
@@ -1687,7 +1692,7 @@ PSDInput::load_layer_channel(Layer& layer, ChannelInfo& channel_info)
16871692 if (!ioread (compressed_data.data (), channel_info.data_length ))
16881693 return false ;
16891694
1690- decompress_zip (compressed_data, channel_info.decompressed_data );
1695+ ok = decompress_zip (compressed_data, channel_info.decompressed_data );
16911696 } break ;
16921697 case Compression_ZIP_Predict: {
16931698 // We subtract the compression marker from the data length
@@ -1704,16 +1709,18 @@ PSDInput::load_layer_channel(Layer& layer, ChannelInfo& channel_info)
17041709 if (!ioread (compressed_data.data (), channel_info.data_length ))
17051710 return false ;
17061711
1707- decompress_zip_prediction (compressed_data,
1708- channel_info.decompressed_data , width,
1709- height);
1712+ ok = decompress_zip_prediction (compressed_data,
1713+ channel_info.decompressed_data , width,
1714+ height);
17101715 } break ;
17111716 default :
17121717 errorfmt (" [Layer Channel] unsupported compression {}" ,
17131718 channel_info.compression );
17141719 return false ;
17151720 }
1716- return true ;
1721+ if (!ok)
1722+ errorfmt (" Error during layer decompression. Possible corrupt file?" );
1723+ return ok;
17171724}
17181725
17191726
@@ -1853,7 +1860,9 @@ PSDInput::load_layers_16_32(uint64_t length)
18531860 ok &= read_bige<int16_t >(layer_info.layer_count );
18541861 if (layer_info.layer_count < 0 ) {
18551862 m_image_data.transparency = true ;
1856- layer_info.layer_count = -layer_info.layer_count ;
1863+ if (layer_info.layer_count == -32768 )
1864+ return false ; // will overflow when negated
1865+ layer_info.layer_count = -layer_info.layer_count ;
18571866 }
18581867 m_layers.resize (layer_info.layer_count );
18591868 for (int16_t layer_nbr = 0 ; layer_nbr < layer_info.layer_count ;
@@ -1894,6 +1903,22 @@ PSDInput::load_image_data()
18941903 compression);
18951904 return false ;
18961905 }
1906+ // Validate that the file has enough channels for its color mode.
1907+ // mode_channel_count gives the minimum channels required; if the layer
1908+ // info section indicated transparency, we need one more channel.
1909+ {
1910+ int required = (m_header.color_mode <= ColorMode_Lab)
1911+ ? (int )mode_channel_count[m_header.color_mode ]
1912+ : 0 ;
1913+ if (m_image_data.transparency )
1914+ required++;
1915+ if (m_header.channel_count < required) {
1916+ errorfmt (
1917+ " [Image Data Section] channel count {} is too few for color mode {}" ,
1918+ m_header.channel_count , m_header.color_mode );
1919+ return false ;
1920+ }
1921+ }
18971922 m_image_data.channel_info .resize (m_header.channel_count );
18981923 // setup some generic properties and read any RLE lengths
18991924 // Image Data Section has RLE lengths for all channels stored first
@@ -1938,7 +1963,7 @@ PSDInput::load_image_data()
19381963
19391964
19401965
1941- void
1966+ bool
19421967PSDInput::setup ()
19431968{
19441969 // raw_channel_count is the number of channels in the file
@@ -2012,6 +2037,8 @@ PSDInput::setup()
20122037 if (layer.name .size ())
20132038 spec.attribute (" oiio:subimagename" , layer.name );
20142039 }
2040+
2041+ return true ;
20152042}
20162043
20172044
@@ -2297,6 +2324,7 @@ bool
22972324PSDInput::decompress_zip (span<char > src, span<char > dest)
22982325{
22992326 z_stream stream {};
2327+ stream.zalloc = Z_NULL;
23002328 stream.zfree = Z_NULL;
23012329 stream.opaque = Z_NULL;
23022330 stream.avail_in = src.size ();
@@ -2306,26 +2334,29 @@ PSDInput::decompress_zip(span<char> src, span<char> dest)
23062334
23072335 if (inflateInit (&stream) != Z_OK) {
23082336 errorfmt (
2309- " zip compression inflate init failed with: src_size={}, dst_size={}" ,
2310- src.size (), dest.size ());
2337+ " zip compression inflate init failed with: src_size={}, dst_size={} {} " ,
2338+ src.size (), dest.size (), stream. msg ? stream. msg : " " );
23112339 return false ;
23122340 }
23132341
2342+ bool ok = true ;
23142343 if (inflate (&stream, Z_FINISH) != Z_STREAM_END) {
23152344 errorfmt (
2316- " unable to decode zip compressed data: src_size={}, dst_size={}" ,
2317- src.size (), dest.size ());
2318- return false ;
2345+ " unable to decode zip compressed data: src_size={}, dst_size={} {} " ,
2346+ src.size (), dest.size (), stream. msg ? stream. msg : " " );
2347+ ok = false ;
23192348 }
23202349
2350+ // Note: call inflateEnd even if ok == false, because we need to clean up.
23212351 if (inflateEnd (&stream) != Z_OK) {
2322- errorfmt (
2323- " zip compression inflate cleanup failed with: src_size={}, dst_size={}" ,
2324- src.size (), dest.size ());
2325- return false ;
2352+ if (ok) // message only if this was the first error
2353+ errorfmt (
2354+ " zip compression inflate cleanup failed with: src_size={}, dst_size={} {}" ,
2355+ src.size (), dest.size (), stream.msg ? stream.msg : " " );
2356+ ok = false ;
23262357 }
23272358
2328- return true ;
2359+ return ok ;
23292360}
23302361
23312362
@@ -2342,6 +2373,8 @@ PSDInput::decompress_zip_prediction(span<char> src, span<char> dest,
23422373
23432374 switch (m_header.depth ) {
23442375 case 8 :
2376+ if ((height - 1 ) * width + (width - 1 ) >= dest.size ())
2377+ return false ; // going to exceed the dest bounds
23452378 for (uint64_t y = 0 ; y < height; ++y) {
23462379 // Index x beginning at one since we look behind to calculate
23472380 // the offset
@@ -2355,6 +2388,8 @@ PSDInput::decompress_zip_prediction(span<char> src, span<char> dest,
23552388 // prediction decoding to work correctly
23562389 span<uint16_t > destView (reinterpret_cast <uint16_t *>(dest.data ()),
23572390 dest.size () / 2 );
2391+ if ((height - 1 ) * width + (width - 1 ) >= destView.size ())
2392+ return false ; // going to exceed the dest bounds
23582393 if (!bigendian ())
23592394 byteswap_span (destView);
23602395
@@ -2373,6 +2408,8 @@ PSDInput::decompress_zip_prediction(span<char> src, span<char> dest,
23732408 for (uint64_t y = 0 ; y < height; ++y) {
23742409 ++index;
23752410 for (uint64_t x = 1 ; x < (width * sizeof (float )); ++x) {
2411+ if (index >= dest.size ())
2412+ return false ; // going to exceed the dest bounds
23762413 uint8_t value = dest[index] + dest[index - 1 ];
23772414 dest[index] = value;
23782415 ++index;
0 commit comments