Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1096)

Unified Diff: src/images/SkImageDecoder_libico.cpp

Issue 996173005: Ico security issues fix (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Added new tests and improved checks Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « resources/invalid_images/ico_leak01.ico ('k') | tests/BadIcoTest.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/images/SkImageDecoder_libico.cpp
diff --git a/src/images/SkImageDecoder_libico.cpp b/src/images/SkImageDecoder_libico.cpp
index 3ca19084daf39aa2e1b7c86e16e69eb55336e005..539d46a364282bf8c08a0ec1b5b5e8f583157e7e 100644
--- a/src/images/SkImageDecoder_libico.cpp
+++ b/src/images/SkImageDecoder_libico.cpp
@@ -76,7 +76,8 @@ SkImageDecoder::Result SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* b
{
SkAutoMalloc autoMal;
const size_t length = SkCopyStreamToStorage(&autoMal, stream);
- if (0 == length) {
+ // Check that the buffer is large enough to read the directory header
+ if (length < 6) {
return kFailure;
}
@@ -91,8 +92,15 @@ SkImageDecoder::Result SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* b
}
int count = read2Bytes(buf, 4);
+ // Check that there are directory entries
+ if (count < 1) {
+ return kFailure;
+ }
- //need to at least have enough space to hold the initial table of info
+ // Check that buffer is large enough to read directory entries.
+ // We are guaranteed that count is at least 1. We might as well assume
+ // count is 1 because this deprecated decoder only looks at the first
+ // directory entry.
if (length < (size_t)(6 + count*16)) {
return kFailure;
}
@@ -102,6 +110,7 @@ SkImageDecoder::Result SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* b
//otherwise, they could be used for error checking
int w = readByte(buf, 6);
int h = readByte(buf, 7);
+ SkASSERT(w >= 0 && h >= 0);
scroggo 2015/03/12 21:19:29 Is this because readByte is guaranteed to return a
msarett 2015/03/12 22:18:22 It is because readByte is guaranteed to return a n
scroggo 2015/03/13 13:43:12 Ah, got it, because buf is defined as pointer to u
int colorCount = readByte(buf, 8);
//int reservedToo = readByte(buf, 9 + choice*16); //0
//int planes = read2Bytes(buf, 10 + choice*16); //1 - but often 0
@@ -109,6 +118,7 @@ SkImageDecoder::Result SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* b
const size_t size = read4Bytes(buf, 14); //matters?
const size_t offset = read4Bytes(buf, 18);
// promote the sum to 64-bits to avoid overflow
+ // Check that buffer is large enough to read image data
if (offset > length || size > length || ((uint64_t)offset + size) > length) {
return kFailure;
}
@@ -139,6 +149,20 @@ SkImageDecoder::Result SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* b
//int width = read4Bytes(buf, offset+4); //should == w
//int height = read4Bytes(buf, offset+8); //should == 2*h
//int planesToo = read2Bytes(buf, offset+12); //should == 1 (does it?)
+
+ // For ico images, only a byte is used to store each dimension
msarett 2015/03/12 15:58:52 The original decoder does not make this check. I
scroggo 2015/03/12 21:19:29 If images in the wild use 0 to mean 256, we should
msarett 2015/03/12 22:18:22 This is how images in the wild are stored. I will
+ // 0 is used to represent 256
+ if (w == 0) {
+ w = 256;
+ }
+ if (h == 0) {
+ h = 256;
+ }
+
+ // Check that buffer is large enough to read the bit depth
+ if (length < offset + 16) {
+ return kFailure;
+ }
int bitCount = read2Bytes(buf, offset+14);
void (*placePixel)(const int pixelNo, const unsigned char* buf,
@@ -180,6 +204,12 @@ SkImageDecoder::Result SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* b
//int colorsImportant = read4Bytes(buf, offset+36); //0
int begin = SkToInt(offset + 40);
+ // Check that the buffer is large enough to read the color table
+ // For bmp-in-icos, there should be 4 bytes per color
+ if (length < begin + 4*colorCount) {
+ return kFailure;
+ }
+
//this array represents the colortable
//if i allow other types of bitmaps, it may actually be used as a part of the bitmap
SkPMColor* colors = NULL;
@@ -228,6 +258,45 @@ SkImageDecoder::Result SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* b
return kFailure;
}
+ // The AND mask is a 1-bit alpha mask for each pixel that comes after the
+ // OR mask in the bmp. If we check that the largest AND offset is safe,
msarett 2015/03/12 15:58:52 This is a type I meant XOR not OR. Will fix in ne
+ // it should mean all other buffer accesses will be at smaller indices and
+ // will therefore be safe.
+ int maxAndOffset = andOffset + ((andLineWidth*(h-1)+(w-1)) >> 3);
+ if (length <= maxAndOffset) {
+ return kFailure;
+ }
+
+ // Here we assert that all reads from the buffer using the XOR offset are
+ // less than the AND offset. This should be guaranteed based on the above
+ // calculations.
+ SkDEBUGCODE(
scroggo 2015/03/12 21:19:29 nit: Typically we use SkDEBUGCODE for one line. Fo
msarett 2015/03/12 22:18:22 Done.
+ int maxPixelNum = lineWidth*(h-1)+w-1;
+ int maxByte;
+ switch (bitCount) {
+ case 1:
+ maxByte = maxPixelNum >> 3;
+ break;
+ case 4:
+ maxByte = maxPixelNum >> 1;
+ break;
+ case 8:
+ maxByte = maxPixelNum;
+ break;
+ case 24:
+ maxByte = maxPixelNum * 3 + 2;
+ break;
+ case 32:
+ maxByte = maxPixelNum * 4 + 3;
+ break;
+ default:
+ SkASSERT(false);
+ return kFailure;
scroggo 2015/03/12 21:19:29 This is strange. We (sort of) do something differe
msarett 2015/03/12 22:18:22 Yes we should never reach here. I will defer to y
scroggo 2015/03/13 13:43:12 I think it's fine as is.
+ }
+ int maxXOROffset = xorOffset + maxByte;
+ );
+ SkASSERT(maxXOROffset < andOffset);
scroggo 2015/03/12 21:19:29 Can you include this inside the SkDEBUGCODE/SK_DEB
msarett 2015/03/12 22:18:22 Yes that will make it easier to understand.
+
SkAutoLockPixels alp(*bm);
for (int y = 0; y < h; y++)
« no previous file with comments | « resources/invalid_images/ico_leak01.ico ('k') | tests/BadIcoTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698