From: Debian QA Group Date: Fri, 6 Nov 2015 13:51:20 +0000 Subject: Fix CVE-2015-0852 CVE-2015-0852: multiple integer underflows in PluginPCX.cpp. --- Source/FreeImage/PluginPCX.cpp | 76 +++++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 26 deletions(-) diff --git a/Source/FreeImage/PluginPCX.cpp b/Source/FreeImage/PluginPCX.cpp index cd75629..dcd9d61 100644 --- a/Source/FreeImage/PluginPCX.cpp +++ b/Source/FreeImage/PluginPCX.cpp @@ -347,12 +347,14 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { try { // check PCX identifier - - long start_pos = io->tell_proc(handle); - BOOL validated = pcx_validate(io, handle); - io->seek_proc(handle, start_pos, SEEK_SET); - if(!validated) { - throw FI_MSG_ERROR_MAGIC_NUMBER; + // (note: should have been already validated using FreeImage_GetFileType but check again) + { + long start_pos = io->tell_proc(handle); + BOOL validated = pcx_validate(io, handle); + io->seek_proc(handle, start_pos, SEEK_SET); + if(!validated) { + throw FI_MSG_ERROR_MAGIC_NUMBER; + } } // process the header @@ -366,20 +368,38 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { SwapHeader(&header); #endif - // allocate a new DIB + // process the window + const WORD *window = header.window; // left, upper, right,lower pixel coord. + const int left = window[0]; + const int top = window[1]; + const int right = window[2]; + const int bottom = window[3]; + + // check image size + if((left >= right) || (top >= bottom)) { + throw FI_MSG_ERROR_PARSING; + } - unsigned width = header.window[2] - header.window[0] + 1; - unsigned height = header.window[3] - header.window[1] + 1; - unsigned bitcount = header.bpp * header.planes; + const unsigned width = right - left + 1; + const unsigned height = bottom - top + 1; + const unsigned bitcount = header.bpp * header.planes; - if (bitcount == 24) { - dib = FreeImage_AllocateHeader(header_only, width, height, bitcount, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); - } else { - dib = FreeImage_AllocateHeader(header_only, width, height, bitcount); + // allocate a new DIB + switch(bitcount) { + case 1: + case 4: + case 8: + dib = FreeImage_AllocateHeader(header_only, width, height, bitcount); + break; + case 24: + dib = FreeImage_AllocateHeader(header_only, width, height, bitcount, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); + break; + default: + throw FI_MSG_ERROR_DIB_MEMORY; + break; } // if the dib couldn't be allocated, throw an error - if (!dib) { throw FI_MSG_ERROR_DIB_MEMORY; } @@ -426,19 +446,23 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { if (palette_id == 0x0C) { BYTE *cmap = (BYTE*)malloc(768 * sizeof(BYTE)); - io->read_proc(cmap, 768, 1, handle); - pal = FreeImage_GetPalette(dib); - BYTE *pColormap = &cmap[0]; + if(cmap) { + io->read_proc(cmap, 768, 1, handle); - for(int i = 0; i < 256; i++) { - pal[i].rgbRed = pColormap[0]; - pal[i].rgbGreen = pColormap[1]; - pal[i].rgbBlue = pColormap[2]; - pColormap += 3; + pal = FreeImage_GetPalette(dib); + BYTE *pColormap = &cmap[0]; + + for(int i = 0; i < 256; i++) { + pal[i].rgbRed = pColormap[0]; + pal[i].rgbGreen = pColormap[1]; + pal[i].rgbBlue = pColormap[2]; + pColormap += 3; + } + + free(cmap); } - free(cmap); } // wrong palette ID, perhaps a gray scale is needed ? @@ -466,9 +490,9 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { // calculate the line length for the PCX and the DIB // length of raster line in bytes - unsigned linelength = header.bytes_per_line * header.planes; + const unsigned linelength = header.bytes_per_line * header.planes; // length of DIB line (rounded to DWORD) in bytes - unsigned pitch = FreeImage_GetPitch(dib); + const unsigned pitch = FreeImage_GetPitch(dib); // run-length encoding ?