r1255 - trunk/code/renderer

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Thu Feb 14 06:12:48 EST 2008


Author: ludwig
Date: 2008-02-14 06:12:42 -0500 (Thu, 14 Feb 2008)
New Revision: 1255

Modified:
   trunk/code/renderer/tr_image.c
Log:
make bmp decoder more robust against corrupt files


Modified: trunk/code/renderer/tr_image.c
===================================================================
--- trunk/code/renderer/tr_image.c	2008-02-12 10:03:43 UTC (rev 1254)
+++ trunk/code/renderer/tr_image.c	2008-02-14 11:12:42 UTC (rev 1255)
@@ -810,20 +810,20 @@
 typedef struct
 {
 	char id[2];
-	unsigned long fileSize;
-	unsigned long reserved0;
-	unsigned long bitmapDataOffset;
-	unsigned long bitmapHeaderSize;
-	unsigned long width;
-	unsigned long height;
+	unsigned fileSize;
+	unsigned reserved0;
+	unsigned bitmapDataOffset;
+	unsigned bitmapHeaderSize;
+	unsigned width;
+	unsigned height;
 	unsigned short planes;
 	unsigned short bitsPerPixel;
-	unsigned long compression;
-	unsigned long bitmapDataSize;
-	unsigned long hRes;
-	unsigned long vRes;
-	unsigned long colors;
-	unsigned long importantColors;
+	unsigned compression;
+	unsigned bitmapDataSize;
+	unsigned hRes;
+	unsigned vRes;
+	unsigned colors;
+	unsigned importantColors;
 	unsigned char palette[256][4];
 } BMPHeader_t;
 
@@ -834,66 +834,90 @@
 	byte	*pixbuf;
 	int		row, column;
 	byte	*buf_p;
-	byte	*buffer;
+	byte	*end;
+	byte	*buffer = NULL;
 	int		length;
 	BMPHeader_t bmpHeader;
 	byte		*bmpRGBA;
 
 	*pic = NULL;
 
+	if(width)
+		*width = 0;
+
+	if(height)
+		*height = 0;
+
 	//
 	// load the file
 	//
 	length = ri.FS_ReadFile( ( char * ) name, (void **)&buffer);
-	if (!buffer) {
+	if (!buffer || length < 0) {
 		return;
 	}
 
+	if (length < 54)
+	{
+		ri.Error( ERR_DROP, "LoadBMP: header too short (%s)\n", name );
+	}
+
 	buf_p = buffer;
+	end = buffer + length;
 
 	bmpHeader.id[0] = *buf_p++;
 	bmpHeader.id[1] = *buf_p++;
-	bmpHeader.fileSize = LittleLong( * ( long * ) buf_p );
+	bmpHeader.fileSize = LittleLong( * ( int * ) buf_p );
 	buf_p += 4;
-	bmpHeader.reserved0 = LittleLong( * ( long * ) buf_p );
+	bmpHeader.reserved0 = LittleLong( * ( int * ) buf_p );
 	buf_p += 4;
-	bmpHeader.bitmapDataOffset = LittleLong( * ( long * ) buf_p );
+	bmpHeader.bitmapDataOffset = LittleLong( * ( int * ) buf_p );
 	buf_p += 4;
-	bmpHeader.bitmapHeaderSize = LittleLong( * ( long * ) buf_p );
+	bmpHeader.bitmapHeaderSize = LittleLong( * ( int * ) buf_p );
 	buf_p += 4;
-	bmpHeader.width = LittleLong( * ( long * ) buf_p );
+	bmpHeader.width = LittleLong( * ( int * ) buf_p );
 	buf_p += 4;
-	bmpHeader.height = LittleLong( * ( long * ) buf_p );
+	bmpHeader.height = LittleLong( * ( int * ) buf_p );
 	buf_p += 4;
 	bmpHeader.planes = LittleShort( * ( short * ) buf_p );
 	buf_p += 2;
 	bmpHeader.bitsPerPixel = LittleShort( * ( short * ) buf_p );
 	buf_p += 2;
-	bmpHeader.compression = LittleLong( * ( long * ) buf_p );
+	bmpHeader.compression = LittleLong( * ( int * ) buf_p );
 	buf_p += 4;
-	bmpHeader.bitmapDataSize = LittleLong( * ( long * ) buf_p );
+	bmpHeader.bitmapDataSize = LittleLong( * ( int * ) buf_p );
 	buf_p += 4;
-	bmpHeader.hRes = LittleLong( * ( long * ) buf_p );
+	bmpHeader.hRes = LittleLong( * ( int * ) buf_p );
 	buf_p += 4;
-	bmpHeader.vRes = LittleLong( * ( long * ) buf_p );
+	bmpHeader.vRes = LittleLong( * ( int * ) buf_p );
 	buf_p += 4;
-	bmpHeader.colors = LittleLong( * ( long * ) buf_p );
+	bmpHeader.colors = LittleLong( * ( int * ) buf_p );
 	buf_p += 4;
-	bmpHeader.importantColors = LittleLong( * ( long * ) buf_p );
+	bmpHeader.importantColors = LittleLong( * ( int * ) buf_p );
 	buf_p += 4;
 
-	Com_Memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) );
-
 	if ( bmpHeader.bitsPerPixel == 8 )
-		buf_p += 1024;
+	{
+		if (buf_p + sizeof(bmpHeader.palette) > end)
+			ri.Error( ERR_DROP, "LoadBMP: header too short (%s)\n", name );
 
+		Com_Memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) );
+		buf_p += sizeof(bmpHeader.palette);
+	}
+
+	if (buffer + bmpHeader.bitmapDataOffset > end)
+	{
+		ri.Error( ERR_DROP, "LoadBMP: invalid offset value in header (%s)\n", name );
+	}
+
+	buf_p = buffer + bmpHeader.bitmapDataOffset;
+
 	if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' ) 
 	{
 		ri.Error( ERR_DROP, "LoadBMP: only Windows-style BMP files supported (%s)\n", name );
 	}
 	if ( bmpHeader.fileSize != length )
 	{
-		ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%d vs. %d) (%s)\n", bmpHeader.fileSize, length, name );
+		ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%u vs. %u) (%s)\n", bmpHeader.fileSize, length, name );
 	}
 	if ( bmpHeader.compression != 0 )
 	{
@@ -904,6 +928,18 @@
 		ri.Error( ERR_DROP, "LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name );
 	}
 
+	switch ( bmpHeader.bitsPerPixel )
+	{
+		case 8:
+		case 16:
+		case 24:
+		case 32:
+			break;
+		default:
+			ri.Error( ERR_DROP, "LoadBMP: illegal pixel_size '%hu' in file '%s'\n", bmpHeader.bitsPerPixel, name );
+			break;
+	}
+
 	columns = bmpHeader.width;
 	rows = bmpHeader.height;
 	if ( rows < 0 )
@@ -915,6 +951,10 @@
 	{
 	  ri.Error (ERR_DROP, "LoadBMP: %s has an invalid image size\n", name);
 	}
+	if(buf_p + numPixels*bmpHeader.bitsPerPixel/8 > end)
+	{
+	  ri.Error (ERR_DROP, "LoadBMP: file truncated (%s)\n", name);
+	}
 
 	if ( width ) 
 		*width = columns;
@@ -972,9 +1012,6 @@
 				*pixbuf++ = blue;
 				*pixbuf++ = alpha;
 				break;
-			default:
-				ri.Error( ERR_DROP, "LoadBMP: illegal pixel_size '%d' in file '%s'\n", bmpHeader.bitsPerPixel, name );
-				break;
 			}
 		}
 	}




More information about the quake3-commits mailing list