Bug 682568 - ICO crash fix for size decodes. r=joe
authorBrian R. Bondy <netzen@gmail.com>
Tue, 30 Aug 2011 01:12:59 -0400
changeset 76208 d97f7df807fc50a83e5f8137964c1d17266a8c7f
parent 76207 f99e149090f5e16746e55878c65837df61a5939d
child 76209 7653363bd293922904e7b60e26d4bc725afd5130
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersjoe
bugs682568
milestone9.0a1
Bug 682568 - ICO crash fix for size decodes. r=joe
modules/libpr0n/decoders/nsBMPDecoder.cpp
modules/libpr0n/decoders/nsICODecoder.cpp
modules/libpr0n/decoders/nsICODecoder.h
--- a/modules/libpr0n/decoders/nsBMPDecoder.cpp
+++ b/modules/libpr0n/decoders/nsBMPDecoder.cpp
@@ -62,16 +62,17 @@ PRLogModuleInfo *gBMPLog = PR_NewLogModu
 // Convert from row (1..height) to absolute line (0..height-1)
 #define LINE(row) ((mBIH.height < 0) ? (-mBIH.height - (row)) : ((row) - 1))
 #define PIXEL_OFFSET(row, col) (LINE(row) * mBIH.width + col)
 
 nsBMPDecoder::nsBMPDecoder()
 {
     mColors = nsnull;
     mRow = nsnull;
+    mImageData = nsnull;
     mCurPos = mPos = mNumColors = mRowBytes = 0;
     mOldLine = mCurLine = 1; // Otherwise decoder will never start
     mState = eRLEStateInitial;
     mStateData = 0;
     mLOH = WIN_HEADER_LENGTH;
     mUseAlphaData = PR_FALSE;
 }
 
--- a/modules/libpr0n/decoders/nsICODecoder.cpp
+++ b/modules/libpr0n/decoders/nsICODecoder.cpp
@@ -179,16 +179,25 @@ PRInt32
 nsICODecoder::ExtractBPPFromBitmap(PRInt8 *bih)
 {
   PRInt32 bitsPerPixel;
   memcpy(&bitsPerPixel, bih + 14, sizeof(bitsPerPixel));
   bitsPerPixel = LITTLE_TO_NATIVE32(bitsPerPixel);
   return bitsPerPixel;
 }
 
+PRInt32 
+nsICODecoder::ExtractBIHSizeFromBitmap(PRInt8 *bih)
+{
+  PRInt32 headerSize;
+  memcpy(&headerSize, bih, sizeof(headerSize));
+  headerSize = LITTLE_TO_NATIVE32(headerSize);
+  return headerSize;
+}
+
 void
 nsICODecoder::SetHotSpotIfCursor() {
   if (!mIsCursor) {
     return;
   }
 
   nsCOMPtr<nsISupportsPRUint32> intwrapx = 
     do_CreateInstance("@mozilla.org/supports-PRUint32;1");
@@ -355,19 +364,26 @@ nsICODecoder::WriteInternal(const char* 
     memcpy(mBIHraw + (mPos - mImageOffset), aBuffer, toCopy);
     mPos += toCopy;
     aCount -= toCopy;
     aBuffer += toCopy;
   }
 
   // If we have a BMP inside the ICO and we have read the BIH header
   if (!mIsPNG && mPos == mImageOffset + BITMAPINFOSIZE) {
+
+    // Make sure we have a sane value for the bitmap information header
+    PRInt32 bihSize = ExtractBIHSizeFromBitmap(reinterpret_cast<PRInt8*>(mBIHraw));
+    if (bihSize != BITMAPINFOSIZE) {
+      PostDataError();
+      return;
+    }
     // We are extracting the BPP from the BIH header as it should be trusted 
     // over the one we have from the icon header
-    mBPP = ExtractBPPFromBitmap((PRInt8*)mBIHraw);
+    mBPP = ExtractBPPFromBitmap(reinterpret_cast<PRInt8*>(mBIHraw));
     
     // Init the bitmap decoder which will do most of the work for us
     // It will do everything except the AND mask which isn't present in bitmaps
     // bmpDecoder is for local scope ease, it will be freed by mContainedDecoder
     nsBMPDecoder *bmpDecoder = new nsBMPDecoder(); 
     mContainedDecoder = bmpDecoder;
     bmpDecoder->SetUseAlphaData(PR_TRUE);
     mContainedDecoder->SetSizeDecode(IsSizeDecode());
@@ -395,16 +411,21 @@ nsICODecoder::WriteInternal(const char* 
 
     // Write out the BMP's bitmap info header
     mContainedDecoder->Write(mBIHraw, sizeof(mBIHraw));
     mDataError = mContainedDecoder->HasDataError();
     if (mContainedDecoder->HasDataError()) {
       return;
     }
 
+    // We have the size. If we're doing a size decode, we got what
+    // we came for.
+    if (IsSizeDecode())
+      return;
+
     // Sometimes the ICO BPP header field is not filled out
     // so we should trust the contained resource over our own
     // information.
     mBPP = bmpDecoder->GetBitsPerPixel();
 
     // Check to make sure we have valid color settings
     PRUint16 numColors = GetNumColors();
     if (numColors == (PRUint16)-1) {
@@ -482,17 +503,22 @@ nsICODecoder::WriteInternal(const char* 
             aCount -= toCopy;
             aBuffer += toCopy;
             mRowBytes += toCopy;
           }
           if (rowSize == mRowBytes) {
             mCurLine--;
             mRowBytes = 0;
 
-            PRUint32* imageData = static_cast<nsBMPDecoder*>(mContainedDecoder.get())->GetImageData();
+            PRUint32* imageData = 
+              static_cast<nsBMPDecoder*>(mContainedDecoder.get())->GetImageData();
+            if (!imageData) {
+              PostDataError();
+              return;
+            }
             PRUint32* decoded = imageData + mCurLine * mDirEntry.mWidth;
             PRUint32* decoded_end = decoded + mDirEntry.mWidth;
             PRUint8* p = mRow, *p_end = mRow + rowSize; 
             while (p < p_end) {
               PRUint8 idx = *p++;
               for (PRUint8 bit = 0x80; bit && decoded<decoded_end; bit >>= 1) {
                 // Clear pixel completely for transparency.
                 if (idx & bit) {
--- a/modules/libpr0n/decoders/nsICODecoder.h
+++ b/modules/libpr0n/decoders/nsICODecoder.h
@@ -68,16 +68,18 @@ private:
   // Processes a single dir entry of the icon resource
   void ProcessDirEntry(IconDirEntry& aTarget);
   // Sets the hotspot property of if we have a cursor
   void SetHotSpotIfCursor();
   // Creates a bitmap file header buffer, returns PR_TRUE if successful
   PRBool FillBitmapFileHeaderBuffer(PRInt8 *bfh);
   // Fixes the height of a BMP information header field
   void FillBitmapInformationBufferHeight(PRInt8 *bih);
+  // Extract bitmap info header size count from BMP information header
+  PRInt32 ExtractBIHSizeFromBitmap(PRInt8 *bih);
   // Extract bit count from BMP information header
   PRInt32 ExtractBPPFromBitmap(PRInt8 *bih);
   // Calculates the row size in bytes for the AND mask table
   PRUint32 CalcAlphaRowSize();
   // Obtains the number of colors from the BPP, mBPP must be filled in
   PRUint16 GetNumColors();
 
   PRUint16 mBPP; // Stores the images BPP