@@ -713,7 +713,9 @@ _Format(-1), _Width(-1), _Height(-1), _WidthBytes(-1), _Size(-1), _CompressedSiz
713713}
714714
715715psdThumbnail::~psdThumbnail () {
716- if (_owned) FreeImage_Unload (_dib);
716+ if (_owned) {
717+ FreeImage_Unload (_dib);
718+ }
717719}
718720
719721void
@@ -771,15 +773,23 @@ int psdThumbnail::Read(FreeImageIO *io, fi_handle handle, int iResourceSize, boo
771773 nBytes += n * sizeof (ShortValue);
772774 _Planes = (short )psdGetValue (ShortValue, sizeof (_Planes) );
773775
776+ if (_WidthBytes * 8 < _Width * _BitPerPixel) {
777+ throw " Invalid PSD image" ;
778+ }
779+
774780 const long JFIF_startpos = io->tell_proc (handle);
775781
776782 if (_dib) {
777783 FreeImage_Unload (_dib);
784+ _dib = nullptr ;
778785 }
779786
780787 if (_Format == 1 ) {
781788 // kJpegRGB thumbnail image
782789 _dib = FreeImage_LoadFromHandle (FIF_JPEG, io, handle);
790+ if (!_dib) {
791+ throw " Invalid PSD thumbnail" ;
792+ }
783793 if (isBGR) {
784794 SwapRedBlue32 (_dib);
785795 }
@@ -789,6 +799,12 @@ int psdThumbnail::Read(FreeImageIO *io, fi_handle handle, int iResourceSize, boo
789799 else {
790800 // kRawRGB thumbnail image
791801 _dib = FreeImage_Allocate (_Width, _Height, _BitPerPixel);
802+ if (!_dib) {
803+ throw " Invalid PSD thumbnail" ;
804+ }
805+ if (_BitPerPixel != FreeImage_GetBPP (_dib)) {
806+ throw " Invalid BPP in PSD thumbnail" ;
807+ }
792808 uint8_t * dst_line_start = FreeImage_GetScanLine (_dib, _Height - 1 );// <*** flipped
793809 auto line_start = std::make_unique<uint8_t []>(_WidthBytes);
794810 const unsigned dstLineSize = FreeImage_GetPitch (_dib);
@@ -1304,45 +1320,49 @@ void psdParser::ReadImageLine(uint8_t* dst, const uint8_t* src, unsigned lineSiz
13041320}
13051321
13061322void psdParser::UnpackRLE (uint8_t * line, const uint8_t * rle_line, const uint8_t * line_end, unsigned srcSize) {
1307- while (srcSize > 0 ) {
1323+ while (srcSize > 1 ) {
1324+ if (line >= line_end) {
1325+ return ;
1326+ }
13081327
1309- int len = *rle_line++;
1328+ const uint8_t len_byte = *rle_line++;
13101329 srcSize--;
13111330
13121331 // NOTE len is signed byte in PackBits RLE
13131332
1314- if ( len < 128 ) { // <- MSB is not set
1333+ if ( len_byte < 128 ) { // <- MSB is not set
13151334 // uncompressed packet
13161335
13171336 // (len + 1) bytes of data are copied
1318- ++ len;
1337+ const uint32_t len = std::min ( static_cast < uint32_t >(len_byte + 1 ), srcSize) ;
13191338
13201339 // assert we don't write beyound eol
13211340 memcpy (line, rle_line, line + len > line_end ? line_end - line : len);
13221341 line += len;
13231342 rle_line += len;
13241343 srcSize -= len;
13251344 }
1326- else if ( len > 128 ) { // < MSB is set
1345+ else if ( len_byte > 128 ) { // < MSB is set
13271346 // RLE compressed packet
13281347
13291348 // One byte of data is repeated (-len + 1) times
13301349
1331- len ^= 0xFF ; // same as (-len + 1) & 0xFF
1332- len += 2 ; //
1350+ // same as (-len + 1) & 0xFF
1351+ const uint32_t len = (len_byte ^ 0xFF ) + 2 ;
13331352
13341353 // assert we don't write beyound eol
13351354 memset (line, *rle_line++, line + len > line_end ? line_end - line : len);
13361355 line += len;
13371356 srcSize--;
13381357 }
1339- else if ( 128 == len ) {
1358+ else {
1359+ // 128 == len
13401360 // Do nothing
13411361 }
13421362 }// < rle_line
13431363}
13441364
1345- FIBITMAP* psdParser::ReadImageData (FreeImageIO * io, fi_handle handle) {
1365+ FIBITMAP* psdParser::ReadImageData (FreeImageIO* io, fi_handle handle) {
13461366 if (!handle) {
13471367 return nullptr ;
13481368 }
@@ -1361,7 +1381,7 @@ FIBITMAP* psdParser::ReadImageData(FreeImageIO *io, fi_handle handle) {
13611381 // PSDP_COMPRESSION_ZIP and PSDP_COMPRESSION_ZIP_PREDICTION
13621382 // are only valid for layer data, not the composited data.
13631383 if (nCompression != PSDP_COMPRESSION_NONE &&
1364- nCompression != PSDP_COMPRESSION_RLE) {
1384+ nCompression != PSDP_COMPRESSION_RLE) {
13651385 FreeImage_OutputMessageProc (_fi_format_id, " Unsupported compression %d" , nCompression);
13661386 return nullptr ;
13671387 }
@@ -1372,6 +1392,25 @@ FIBITMAP* psdParser::ReadImageData(FreeImageIO *io, fi_handle handle) {
13721392 const unsigned depth = _headerInfo._BitsPerChannel ;
13731393 const unsigned bytes = (depth == 1 ) ? 1 : depth / 8 ;
13741394
1395+ // https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/
1396+ if (nChannels < 1 || nChannels > 56 ) {
1397+ throw " Invalid channels value in PSD header" ;
1398+ }
1399+
1400+ if (nWidth < 1 || nWidth > 30000 || nHeight < 1 || nHeight > 30000 ) {
1401+ throw " Invalid width or height value in PSD header" ;
1402+ }
1403+
1404+ switch (depth) {
1405+ case 1 :
1406+ case 8 :
1407+ case 16 :
1408+ case 32 :
1409+ break ;
1410+ default :
1411+ throw " Invalid depth value in PSD header" ;
1412+ }
1413+
13751414 // channel(plane) line (uint8_t aligned)
13761415 const unsigned lineSize = (_headerInfo._BitsPerChannel == 1 ) ? (nWidth + 7 ) / 8 : nWidth * bytes;
13771416
@@ -1460,6 +1499,10 @@ FIBITMAP* psdParser::ReadImageData(FreeImageIO *io, fi_handle handle) {
14601499 const unsigned dstLineSize = FreeImage_GetPitch (bitmap);
14611500 uint8_t * const dst_first_line = FreeImage_GetScanLine (bitmap, nHeight - 1 );// <*** flipped
14621501
1502+ if (lineSize > dstLineSize) {
1503+ throw " Invalid source size" ;
1504+ }
1505+
14631506 auto line_start = std::make_unique<uint8_t []>(lineSize); // < fileline cache
14641507
14651508 switch ( nCompression ) {
0 commit comments