Index: src/images/SkImageDecoder_libico.cpp |
diff --git a/src/images/SkImageDecoder_libico.cpp b/src/images/SkImageDecoder_libico.cpp |
index 3ca19084daf39aa2e1b7c86e16e69eb55336e005..fc45bb85ee8f11e16206bc2689c1177ec2256379 100644 |
--- a/src/images/SkImageDecoder_libico.cpp |
+++ b/src/images/SkImageDecoder_libico.cpp |
@@ -82,6 +82,10 @@ SkImageDecoder::Result SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* b |
unsigned char* buf = (unsigned char*)autoMal.get(); |
+ // Check that the buffer is large enough to read the directory header |
+ if (length < 6) { |
scroggo
2015/03/12 13:25:54
Why not merge this with the earlier check? We did
|
+ return kFailure; |
+ } |
//these should always be the same - should i use for error checking? - what about files that have some |
//incorrect values, but still decode properly? |
int reserved = read2Bytes(buf, 0); // 0 |
@@ -91,8 +95,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; |
} |
@@ -109,6 +120,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 +151,11 @@ 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?) |
+ |
+ // 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 +197,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 |
+ int bytesPerColor = 4; |
scroggo
2015/03/12 13:25:54
This can be inlined, since it's only used once. (M
msarett
2015/03/12 15:58:52
Sure. FWIW, 4 shows up in the code later. We cou
|
+ if (length < begin + bytesPerColor*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 +251,14 @@ SkImageDecoder::Result SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* b |
return kFailure; |
} |
+ // The AND mask comes after the OR mask in the bmp. If we check that the |
+ // largest AND offset is safe, 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); |
scroggo
2015/03/12 13:25:54
nit: This seems like it's the max offset of the al
msarett
2015/03/12 15:58:52
The AND mask is a 1 bit mask for each pixel indica
|
+ if (length <= maxAndOffset) { |
+ return kFailure; |
+ } |
+ |
SkAutoLockPixels alp(*bm); |
for (int y = 0; y < h; y++) |