From 5792cded61a7302f32bd0f4aeda51a9b2f1d00f6 Mon Sep 17 00:00:00 2001 From: "commit-bot@chromium.org" Date: Fri, 13 Sep 2013 12:39:34 +0000 Subject: [PATCH] Initial error handling code I made it as simple as possible. The impact seems minimal and it should do what's necessary to make this code secure. BUG= R=reed@google.com, scroggo@google.com, djsollen@google.com, sugoi@google.com, bsalomon@google.com, mtklein@google.com, senorblanco@google.com, senorblanco@chromium.org Author: sugoi@chromium.org Review URL: https://chromiumcodereview.appspot.com/23021015 git-svn-id: http://skia.googlecode.com/svn/trunk@11247 2bbb7eff-a529-9590-31e7-b0007b416f81 --- gyp/core.gypi | 1 + include/core/SkBitmap.h | 1 + include/core/SkFlattenableBuffers.h | 26 +- include/core/SkFlattenableSerialization.h | 10 +- include/core/SkRect.h | 4 + src/core/SkBitmap.cpp | 8 +- src/core/SkFlattenableBuffers.cpp | 3 +- src/core/SkFlattenableSerialization.cpp | 12 +- src/core/SkImageFilter.cpp | 2 + src/core/SkOrderedWriteBuffer.cpp | 13 +- src/core/SkValidatingReadBuffer.cpp | 290 ++++++++++++++++++ src/core/SkValidatingReadBuffer.h | 141 +++++++++ src/core/SkValidationUtils.h | 46 +++ src/core/SkXfermode.cpp | 5 + src/effects/SkBicubicImageFilter.cpp | 4 + src/effects/SkBlurImageFilter.cpp | 4 + src/effects/SkColorFilters.cpp | 2 + src/effects/SkColorMatrixFilter.cpp | 3 + src/effects/SkDisplacementMapEffect.cpp | 17 + src/effects/SkDropShadowImageFilter.cpp | 3 + src/effects/SkLightingImageFilter.cpp | 11 + src/effects/SkMagnifierImageFilter.cpp | 3 + .../SkMatrixConvolutionImageFilter.cpp | 19 ++ src/effects/SkMergeImageFilter.cpp | 7 +- src/effects/SkMorphologyImageFilter.cpp | 4 + src/effects/SkOffsetImageFilter.cpp | 2 + src/effects/SkRectShaderImageFilter.cpp | 2 + src/effects/SkTestImageFilters.cpp | 1 + 28 files changed, 628 insertions(+), 16 deletions(-) create mode 100644 src/core/SkValidatingReadBuffer.cpp create mode 100644 src/core/SkValidatingReadBuffer.h create mode 100644 src/core/SkValidationUtils.h diff --git a/gyp/core.gypi b/gyp/core.gypi index 6c00a56763..a25173dd24 100644 --- a/gyp/core.gypi +++ b/gyp/core.gypi @@ -164,6 +164,7 @@ '<(skia_src_path)/core/SkScan_Antihair.cpp', '<(skia_src_path)/core/SkScan_Hairline.cpp', '<(skia_src_path)/core/SkScan_Path.cpp', + '<(skia_src_path)/core/SkValidatingReadBuffer.cpp', '<(skia_src_path)/core/SkShader.cpp', '<(skia_src_path)/core/SkSpriteBlitter_ARGB32.cpp', '<(skia_src_path)/core/SkSpriteBlitter_RGB16.cpp', diff --git a/include/core/SkBitmap.h b/include/core/SkBitmap.h index 887169ccb5..79b6fa6703 100644 --- a/include/core/SkBitmap.h +++ b/include/core/SkBitmap.h @@ -52,6 +52,7 @@ public: kRGB_565_Config, //!< 16-bits per pixel, (see SkColorPriv.h for packing) kARGB_4444_Config, //!< 16-bits per pixel, (see SkColorPriv.h for packing) kARGB_8888_Config, //!< 32-bits per pixel, (see SkColorPriv.h for packing) + kLastConfig = kARGB_8888_Config, }; // do not add this to the Config enum, otherwise the compiler will let us diff --git a/include/core/SkFlattenableBuffers.h b/include/core/SkFlattenableBuffers.h index 03c03f3877..b3f3684daa 100644 --- a/include/core/SkFlattenableBuffers.h +++ b/include/core/SkFlattenableBuffers.h @@ -41,14 +41,20 @@ public: kCrossProcess_Flag = 1 << 0, kScalarIsFloat_Flag = 1 << 1, kPtrIs64Bit_Flag = 1 << 2, + /** The kValidation_Flag is used to force stream validations (by making + * sure that no operation reads past the end of the stream, for example) + * and error handling if any reading operation yields an invalid value. + */ + kValidation_Flag = 1 << 3, }; void setFlags(uint32_t flags) { fFlags = flags; } uint32_t getFlags() const { return fFlags; } - bool isCrossProcess() const { return SkToBool(fFlags & kCrossProcess_Flag); } + bool isCrossProcess() const { return SkToBool(fFlags & (kCrossProcess_Flag | kValidation_Flag)); } bool isScalarFloat() const { return SkToBool(fFlags & kScalarIsFloat_Flag); } bool isPtr64Bit() const { return SkToBool(fFlags & kPtrIs64Bit_Flag); } + bool isValidating() const { return SkToBool(fFlags & kValidation_Flag); } // primitives virtual bool readBool() = 0; @@ -102,6 +108,13 @@ public: return static_cast(this->readFlattenable()); } + void validate(bool isValid) { + fError |= !isValid; + } + +protected: + bool fError; + private: uint32_t fFlags; }; @@ -154,13 +167,22 @@ public: enum Flags { kCrossProcess_Flag = 0x01, + /** The kValidation_Flag is used here to make sure the write operation + * is symmetric with the read operation using the equivalent flag + * SkFlattenableReadBuffer::kValidation_Flag. + */ + kValidation_Flag = 0x02, }; uint32_t getFlags() const { return fFlags; } void setFlags(uint32_t flags) { fFlags = flags; } bool isCrossProcess() const { - return SkToBool(fFlags & kCrossProcess_Flag); + return SkToBool(fFlags & (kCrossProcess_Flag | kValidation_Flag)); + } + + bool isValidating() const { + return SkToBool(fFlags & kValidation_Flag); } bool persistTypeface() const { return (fFlags & kCrossProcess_Flag) != 0; } diff --git a/include/core/SkFlattenableSerialization.h b/include/core/SkFlattenableSerialization.h index 2ed244c1ed..33bbb38a9b 100644 --- a/include/core/SkFlattenableSerialization.h +++ b/include/core/SkFlattenableSerialization.h @@ -13,7 +13,13 @@ class SkData; class SkFlattenable; -SK_API SkData* SkSerializeFlattenable(SkFlattenable*); -SK_API SkFlattenable* SkDeserializeFlattenable(const void* data, size_t size); +/** + * These utility functions are used by the chromium codebase to safely + * serialize and deserialize SkFlattenable objects. These aren't made for + * optimal speed, but rather designed with security in mind in order to + * prevent Skia from being an entry point for potential attacks. + */ +SK_API SkData* SkValidatingSerializeFlattenable(SkFlattenable*); +SK_API SkFlattenable* SkValidatingDeserializeFlattenable(const void* data, size_t size); #endif diff --git a/include/core/SkRect.h b/include/core/SkRect.h index d8919ae5d6..bd5d026d50 100644 --- a/include/core/SkRect.h +++ b/include/core/SkRect.h @@ -100,6 +100,8 @@ struct SK_API SkIRect { */ bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } + bool isInverted() const { return fLeft > fRight || fTop > fBottom; } + bool isLargest() const { return SK_MinS32 == fLeft && SK_MinS32 == fTop && SK_MaxS32 == fRight && @@ -419,6 +421,8 @@ struct SK_API SkRect { */ bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } + bool isInverted() const { return fLeft > fRight || fTop > fBottom; } + /** * Returns true iff all values in the rect are finite. If any are * infinite or NaN (or SK_FixedNaN when SkScalar is fixed) then this diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp index d3bbecd706..762abc0bf1 100644 --- a/src/core/SkBitmap.cpp +++ b/src/core/SkBitmap.cpp @@ -19,6 +19,7 @@ #include "SkThread.h" #include "SkUnPreMultiply.h" #include "SkUtils.h" +#include "SkValidationUtils.h" #include "SkPackBits.h" #include @@ -1607,9 +1608,11 @@ void SkBitmap::unflatten(SkFlattenableReadBuffer& buffer) { int width = buffer.readInt(); int height = buffer.readInt(); int rowBytes = buffer.readInt(); - int config = buffer.readInt(); + Config config = (Config)buffer.readInt(); + buffer.validate((width >= 0) && (height >= 0) && (rowBytes >= 0) && + SkIsValidConfig(config)); - this->setConfig((Config)config, width, height, rowBytes); + this->setConfig(config, width, height, rowBytes); this->setIsOpaque(buffer.readBool()); int reftype = buffer.readInt(); @@ -1623,6 +1626,7 @@ void SkBitmap::unflatten(SkFlattenableReadBuffer& buffer) { case SERIALIZE_PIXELTYPE_NONE: break; default: + buffer.validate(false); SkDEBUGFAIL("unrecognized pixeltype in serialized data"); sk_throw(); } diff --git a/src/core/SkFlattenableBuffers.cpp b/src/core/SkFlattenableBuffers.cpp index 50a47d5c47..72cd492cd8 100644 --- a/src/core/SkFlattenableBuffers.cpp +++ b/src/core/SkFlattenableBuffers.cpp @@ -9,7 +9,8 @@ #include "SkPaint.h" #include "SkTypeface.h" -SkFlattenableReadBuffer::SkFlattenableReadBuffer() { +SkFlattenableReadBuffer::SkFlattenableReadBuffer() : + fError(false) { // Set default values. These should be explicitly set by our client // via setFlags() if the buffer came from serialization. fFlags = 0; diff --git a/src/core/SkFlattenableSerialization.cpp b/src/core/SkFlattenableSerialization.cpp index b74c82f051..63180532d9 100644 --- a/src/core/SkFlattenableSerialization.cpp +++ b/src/core/SkFlattenableSerialization.cpp @@ -9,12 +9,12 @@ #include "SkData.h" #include "SkFlattenable.h" -#include "SkOrderedReadBuffer.h" +#include "SkValidatingReadBuffer.h" #include "SkOrderedWriteBuffer.h" -SkData* SkSerializeFlattenable(SkFlattenable* flattenable) { +SkData* SkValidatingSerializeFlattenable(SkFlattenable* flattenable) { SkOrderedWriteBuffer writer(1024); - writer.setFlags(SkOrderedWriteBuffer::kCrossProcess_Flag); + writer.setFlags(SkOrderedWriteBuffer::kValidation_Flag); writer.writeFlattenable(flattenable); uint32_t size = writer.bytesWritten(); void* data = sk_malloc_throw(size); @@ -22,7 +22,7 @@ SkData* SkSerializeFlattenable(SkFlattenable* flattenable) { return SkData::NewFromMalloc(data, size); } -SkFlattenable* SkDeserializeFlattenable(const void* data, size_t size) { - SkOrderedReadBuffer buffer(data, size); - return buffer.readFlattenable(); +SkFlattenable* SkValidatingDeserializeFlattenable(const void* data, size_t size) { + SkValidatingReadBuffer reader(data, size); + return reader.readFlattenable(); } diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp index 502613bb68..89b2cc50d8 100644 --- a/src/core/SkImageFilter.cpp +++ b/src/core/SkImageFilter.cpp @@ -10,6 +10,7 @@ #include "SkBitmap.h" #include "SkFlattenableBuffers.h" #include "SkRect.h" +#include "SkValidationUtils.h" #if SK_SUPPORT_GPU #include "GrContext.h" #include "GrTexture.h" @@ -62,6 +63,7 @@ SkImageFilter::SkImageFilter(SkFlattenableReadBuffer& buffer) } } buffer.readIRect(&fCropRect); + buffer.validate(SkIsValidRect(fCropRect)); } void SkImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const { diff --git a/src/core/SkOrderedWriteBuffer.cpp b/src/core/SkOrderedWriteBuffer.cpp index 64f52193ac..8904d7cde1 100644 --- a/src/core/SkOrderedWriteBuffer.cpp +++ b/src/core/SkOrderedWriteBuffer.cpp @@ -270,7 +270,9 @@ void SkOrderedWriteBuffer::writeFlattenable(SkFlattenable* flattenable) { factory = flattenable->getFactory(); } if (NULL == factory) { - if (fFactorySet != NULL || fNamedFactorySet != NULL) { + if (this->isValidating()) { + this->writeString(NULL); + } else if (fFactorySet != NULL || fNamedFactorySet != NULL) { this->write32(0); } else { this->writeFunctionPtr(NULL); @@ -290,7 +292,14 @@ void SkOrderedWriteBuffer::writeFlattenable(SkFlattenable* flattenable) { * name. SkGPipe uses this technique so it can write the name to its * stream before writing the flattenable. */ - if (fFactorySet) { + if (this->isValidating()) { + const char* name = SkFlattenable::FactoryToName(factory); + this->writeString(name); + if (NULL == name) { + SkASSERT(!"Missing factory name"); + return; + } + } else if (fFactorySet) { this->write32(fFactorySet->add(factory)); } else if (fNamedFactorySet) { int32_t index = fNamedFactorySet->find(factory); diff --git a/src/core/SkValidatingReadBuffer.cpp b/src/core/SkValidatingReadBuffer.cpp new file mode 100644 index 0000000000..b8247ab566 --- /dev/null +++ b/src/core/SkValidatingReadBuffer.cpp @@ -0,0 +1,290 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkBitmap.h" +#include "SkErrorInternals.h" +#include "SkValidatingReadBuffer.h" +#include "SkStream.h" +#include "SkTypeface.h" + +SkValidatingReadBuffer::SkValidatingReadBuffer() : INHERITED() { + fMemoryPtr = NULL; + + fBitmapStorage = NULL; + fTFArray = NULL; + fTFCount = 0; + + fFactoryTDArray = NULL; + fFactoryArray = NULL; + fFactoryCount = 0; + fBitmapDecoder = NULL; +#ifdef DEBUG_NON_DETERMINISTIC_ASSERT + fDecodedBitmapIndex = -1; +#endif // DEBUG_NON_DETERMINISTIC_ASSERT + + setFlags(SkFlattenableReadBuffer::kValidation_Flag); +} + +SkValidatingReadBuffer::SkValidatingReadBuffer(const void* data, size_t size) : INHERITED() { + this->setMemory(data, size); + fMemoryPtr = NULL; + + fBitmapStorage = NULL; + fTFArray = NULL; + fTFCount = 0; + + fFactoryTDArray = NULL; + fFactoryArray = NULL; + fFactoryCount = 0; + fBitmapDecoder = NULL; +#ifdef DEBUG_NON_DETERMINISTIC_ASSERT + fDecodedBitmapIndex = -1; +#endif // DEBUG_NON_DETERMINISTIC_ASSERT + + setFlags(SkFlattenableReadBuffer::kValidation_Flag); +} + +SkValidatingReadBuffer::SkValidatingReadBuffer(SkStream* stream) { + const size_t length = stream->getLength(); + fMemoryPtr = sk_malloc_throw(length); + stream->read(fMemoryPtr, length); + this->setMemory(fMemoryPtr, length); + + fBitmapStorage = NULL; + fTFArray = NULL; + fTFCount = 0; + + fFactoryTDArray = NULL; + fFactoryArray = NULL; + fFactoryCount = 0; + fBitmapDecoder = NULL; +#ifdef DEBUG_NON_DETERMINISTIC_ASSERT + fDecodedBitmapIndex = -1; +#endif // DEBUG_NON_DETERMINISTIC_ASSERT + + setFlags(SkFlattenableReadBuffer::kValidation_Flag); +} + +SkValidatingReadBuffer::~SkValidatingReadBuffer() { + sk_free(fMemoryPtr); + SkSafeUnref(fBitmapStorage); +} + +void SkValidatingReadBuffer::setMemory(const void* data, size_t size) { + fError |= (!ptr_align_4(data) || (SkAlign4(size) != size)); + if (!fError) { + fReader.setMemory(data, size); + } +} + +const void* SkValidatingReadBuffer::skip(size_t size) { + size_t inc = SkAlign4(size); + const void* addr = fReader.peek(); + fError |= !ptr_align_4(addr) || !fReader.isAvailable(inc); + if (!fError) { + fReader.skip(size); + } + return addr; +} + +bool SkValidatingReadBuffer::readBool() { + return this->readInt() != 0; +} + +SkColor SkValidatingReadBuffer::readColor() { + return this->readInt(); +} + +SkFixed SkValidatingReadBuffer::readFixed() { + return this->readInt(); +} + +int32_t SkValidatingReadBuffer::readInt() { + size_t inc = sizeof(int32_t); + fError |= !ptr_align_4(fReader.peek()) || !fReader.isAvailable(inc); + return fError ? 0 : fReader.readInt(); +} + +SkScalar SkValidatingReadBuffer::readScalar() { + size_t inc = sizeof(SkScalar); + fError |= !ptr_align_4(fReader.peek()) || !fReader.isAvailable(inc); + return fError ? 0 : fReader.readScalar(); +} + +uint32_t SkValidatingReadBuffer::readUInt() { + return this->readInt(); +} + +int32_t SkValidatingReadBuffer::read32() { + return this->readInt(); +} + +void SkValidatingReadBuffer::readString(SkString* string) { + size_t len = this->readInt(); + const void* ptr = fReader.peek(); + + // skip over the string + '\0' and then pad to a multiple of 4 + size_t alignedSize = SkAlign4(len + 1); + this->skip(alignedSize); + if (!fError) { + string->set((const char*)ptr, len); + } +} + +void* SkValidatingReadBuffer::readEncodedString(size_t* length, SkPaint::TextEncoding encoding) { + int32_t encodingType = fReader.readInt(); + if (encodingType == encoding) { + fError = true; + } + *length = this->readInt(); + const void* ptr = this->skip(SkAlign4(*length)); + void* data = NULL; + if (!fError) { + data = sk_malloc_throw(*length); + memcpy(data, ptr, *length); + } + return data; +} + +void SkValidatingReadBuffer::readPoint(SkPoint* point) { + point->fX = fReader.readScalar(); + point->fY = fReader.readScalar(); +} + +void SkValidatingReadBuffer::readMatrix(SkMatrix* matrix) { + size_t size = matrix->readFromMemory(fReader.peek()); + fError |= (SkAlign4(size) != size); + if (!fError) { + (void)this->skip(size); + } +} + +void SkValidatingReadBuffer::readIRect(SkIRect* rect) { + memcpy(rect, this->skip(sizeof(SkIRect)), sizeof(SkIRect)); +} + +void SkValidatingReadBuffer::readRect(SkRect* rect) { + memcpy(rect, this->skip(sizeof(SkRect)), sizeof(SkRect)); +} + +void SkValidatingReadBuffer::readRegion(SkRegion* region) { + size_t size = region->readFromMemory(fReader.peek()); + fError |= (SkAlign4(size) != size); + if (!fError) { + (void)this->skip(size); + } +} + +void SkValidatingReadBuffer::readPath(SkPath* path) { + size_t size = path->readFromMemory(fReader.peek()); + fError |= (SkAlign4(size) != size); + if (!fError) { + (void)this->skip(size); + } +} + +uint32_t SkValidatingReadBuffer::readByteArray(void* value) { + const uint32_t length = this->readUInt(); + memcpy(value, this->skip(SkAlign4(length)), length); + return fError ? 0 : length; +} + +uint32_t SkValidatingReadBuffer::readColorArray(SkColor* colors) { + const uint32_t count = this->readUInt(); + const uint32_t byteLength = count * sizeof(SkColor); + memcpy(colors, this->skip(SkAlign4(byteLength)), byteLength); + return fError ? 0 : count; +} + +uint32_t SkValidatingReadBuffer::readIntArray(int32_t* values) { + const uint32_t count = this->readUInt(); + const uint32_t byteLength = count * sizeof(int32_t); + memcpy(values, this->skip(SkAlign4(byteLength)), byteLength); + return fError ? 0 : count; +} + +uint32_t SkValidatingReadBuffer::readPointArray(SkPoint* points) { + const uint32_t count = this->readUInt(); + const uint32_t byteLength = count * sizeof(SkPoint); + memcpy(points, this->skip(SkAlign4(byteLength)), byteLength); + return fError ? 0 : count; +} + +uint32_t SkValidatingReadBuffer::readScalarArray(SkScalar* values) { + const uint32_t count = this->readUInt(); + const uint32_t byteLength = count * sizeof(SkScalar); + memcpy(values, this->skip(SkAlign4(byteLength)), byteLength); + return fError ? 0 : count; +} + +uint32_t SkValidatingReadBuffer::getArrayCount() { + return *(uint32_t*)fReader.peek(); +} + +void SkValidatingReadBuffer::readBitmap(SkBitmap* bitmap) { + const int width = this->readInt(); + const int height = this->readInt(); + const size_t length = this->readUInt(); + // A size of zero means the SkBitmap was simply flattened. + if (length != 0) { + fError = true; + } + if (fError) { + return; + } + bitmap->unflatten(*this); + if ((bitmap->width() != width) || (bitmap->height() != height)) { + fError = true; + } +} + +SkTypeface* SkValidatingReadBuffer::readTypeface() { + + uint32_t index = this->readUInt(); + if (0 == index || index > (unsigned)fTFCount || fError) { + if (index) { + SkDebugf("====== typeface index %d\n", index); + } + return NULL; + } else { + SkASSERT(fTFArray); + return fTFArray[index - 1]; + } +} + +SkFlattenable* SkValidatingReadBuffer::readFlattenable() { + SkString string; + this->readString(&string); + if (fError) { + return NULL; + } + SkFlattenable::Factory factory = SkFlattenable::NameToFactory(string.c_str()); + if (NULL == factory) { + return NULL; // writer failed to give us the flattenable + } + + // if we get here, factory may still be null, but if that is the case, the + // failure was ours, not the writer. + SkFlattenable* obj = NULL; + uint32_t sizeRecorded = this->readUInt(); + if (factory) { + uint32_t offset = fReader.offset(); + obj = (*factory)(*this); + // check that we read the amount we expected + uint32_t sizeRead = fReader.offset() - offset; + if (sizeRecorded != sizeRead) { + // we could try to fix up the offset... + fError = true; + delete obj; + obj = NULL; + } + } else { + // we must skip the remaining data + this->skip(sizeRecorded); + } + return obj; +} diff --git a/src/core/SkValidatingReadBuffer.h b/src/core/SkValidatingReadBuffer.h new file mode 100644 index 0000000000..accf5d75f9 --- /dev/null +++ b/src/core/SkValidatingReadBuffer.h @@ -0,0 +1,141 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkValidatingReadBuffer_DEFINED +#define SkValidatingReadBuffer_DEFINED + +#include "SkRefCnt.h" +#include "SkBitmapHeap.h" +#include "SkFlattenableBuffers.h" +#include "SkPath.h" +#include "SkPicture.h" +#include "SkReader32.h" + +class SkBitmap; + +#if defined(SK_DEBUG) && defined(SK_BUILD_FOR_MAC) + #define DEBUG_NON_DETERMINISTIC_ASSERT +#endif + +class SkValidatingReadBuffer : public SkFlattenableReadBuffer { +public: + SkValidatingReadBuffer(); + SkValidatingReadBuffer(const void* data, size_t size); + SkValidatingReadBuffer(SkStream* stream); + virtual ~SkValidatingReadBuffer(); + + SkReader32* getReader32() { return &fReader; } + + uint32_t size() { return fReader.size(); } + uint32_t offset() { return fReader.offset(); } + bool eof() { return fReader.eof(); } + const void* skip(size_t size); + + // primitives + virtual bool readBool() SK_OVERRIDE; + virtual SkColor readColor() SK_OVERRIDE; + virtual SkFixed readFixed() SK_OVERRIDE; + virtual int32_t readInt() SK_OVERRIDE; + virtual SkScalar readScalar() SK_OVERRIDE; + virtual uint32_t readUInt() SK_OVERRIDE; + virtual int32_t read32() SK_OVERRIDE; + + // strings -- the caller is responsible for freeing the string contents + virtual void readString(SkString* string) SK_OVERRIDE; + virtual void* readEncodedString(size_t* length, SkPaint::TextEncoding encoding) SK_OVERRIDE; + + // common data structures + virtual SkFlattenable* readFlattenable() SK_OVERRIDE; + virtual void readPoint(SkPoint* point) SK_OVERRIDE; + virtual void readMatrix(SkMatrix* matrix) SK_OVERRIDE; + virtual void readIRect(SkIRect* rect) SK_OVERRIDE; + virtual void readRect(SkRect* rect) SK_OVERRIDE; + virtual void readRegion(SkRegion* region) SK_OVERRIDE; + virtual void readPath(SkPath* path) SK_OVERRIDE; + + // binary data and arrays + virtual uint32_t readByteArray(void* value) SK_OVERRIDE; + virtual uint32_t readColorArray(SkColor* colors) SK_OVERRIDE; + virtual uint32_t readIntArray(int32_t* values) SK_OVERRIDE; + virtual uint32_t readPointArray(SkPoint* points) SK_OVERRIDE; + virtual uint32_t readScalarArray(SkScalar* values) SK_OVERRIDE; + + // helpers to get info about arrays and binary data + virtual uint32_t getArrayCount() SK_OVERRIDE; + + virtual void readBitmap(SkBitmap* bitmap) SK_OVERRIDE; + virtual SkTypeface* readTypeface() SK_OVERRIDE; + + void setBitmapStorage(SkBitmapHeapReader* bitmapStorage) { + SkRefCnt_SafeAssign(fBitmapStorage, bitmapStorage); + } + + void setTypefaceArray(SkTypeface* array[], int count) { + fTFArray = array; + fTFCount = count; + } + + /** + * Call this with a pre-loaded array of Factories, in the same order as + * were created/written by the writer. SkPicture uses this. + */ + void setFactoryPlayback(SkFlattenable::Factory array[], int count) { + fFactoryTDArray = NULL; + fFactoryArray = array; + fFactoryCount = count; + } + + /** + * Call this with an initially empty array, so the reader can cache each + * factory it sees by name. Used by the pipe code in conjunction with + * SkOrderedWriteBuffer::setNamedFactoryRecorder. + */ + void setFactoryArray(SkTDArray* array) { + fFactoryTDArray = array; + fFactoryArray = NULL; + fFactoryCount = 0; + } + + /** + * Provide a function to decode an SkBitmap from encoded data. Only used if the writer + * encoded the SkBitmap. If the proper decoder cannot be used, a red bitmap with the + * appropriate size will be used. + */ + void setBitmapDecoder(SkPicture::InstallPixelRefProc bitmapDecoder) { + fBitmapDecoder = bitmapDecoder; + } + +private: + void setMemory(const void* data, size_t size); + + static bool ptr_align_4(const void* ptr) { + return (((const char*)ptr - (const char*)NULL) & 3) == 0; + } + + SkReader32 fReader; + void* fMemoryPtr; + + SkBitmapHeapReader* fBitmapStorage; + SkTypeface** fTFArray; + int fTFCount; + + SkTDArray* fFactoryTDArray; + SkFlattenable::Factory* fFactoryArray; + int fFactoryCount; + + SkPicture::InstallPixelRefProc fBitmapDecoder; + +#ifdef DEBUG_NON_DETERMINISTIC_ASSERT + // Debugging counter to keep track of how many bitmaps we + // have decoded. + int fDecodedBitmapIndex; +#endif // DEBUG_NON_DETERMINISTIC_ASSERT + + typedef SkFlattenableReadBuffer INHERITED; +}; + +#endif // SkValidatingReadBuffer_DEFINED diff --git a/src/core/SkValidationUtils.h b/src/core/SkValidationUtils.h new file mode 100644 index 0000000000..f31d86ce22 --- /dev/null +++ b/src/core/SkValidationUtils.h @@ -0,0 +1,46 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkValidationUtils_DEFINED +#define SkValidationUtils_DEFINED + +#include "SkBitmap.h" +#include "SkXfermode.h" + +/** Returns true if coeff's value is in the SkXfermode::Coeff enum. + */ +static inline bool SkIsValidCoeff(SkXfermode::Coeff coeff) { + return coeff >= 0 && coeff < SkXfermode::kCoeffCount; +} + +/** Returns true if mode's value is in the SkXfermode::Mode enum. + */ +static inline bool SkIsValidMode(SkXfermode::Mode mode) { + return (mode >= 0) && (mode <= SkXfermode::kLastMode); +} + +/** Returns true if config's value is in the SkBitmap::Config enum. + */ +static inline bool SkIsValidConfig(SkBitmap::Config config) { + return (config >= 0) && (config <= SkBitmap::kLastConfig); +} + +/** Returns true if the rect's dimensions are between 0 and SK_MaxS32 + */ +static inline bool SkIsValidRect(const SkIRect& rect) { + return rect.width() >= 0 && rect.height() >= 0; +} + +/** Returns true if the rect's dimensions are between 0 and SK_ScalarMax + */ +static inline bool SkIsValidRect(const SkRect& rect) { + return !rect.isInverted() && + SkScalarIsFinite(rect.width()) && + SkScalarIsFinite(rect.height()); +} + +#endif diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp index ac5cee4e35..9c5ccccd92 100644 --- a/src/core/SkXfermode.cpp +++ b/src/core/SkXfermode.cpp @@ -12,6 +12,7 @@ #include "SkFlattenableBuffers.h" #include "SkMathPriv.h" #include "SkString.h" +#include "SkValidationUtils.h" SK_DEFINE_INST_COUNT(SkXfermode) @@ -1438,6 +1439,10 @@ protected: fDstCoeff = rec.fDC; // now update our function-ptr in the super class this->INHERITED::setProc(rec.fProc); + + buffer.validate(SkIsValidMode(fMode) && + SkIsValidCoeff(fSrcCoeff) && + SkIsValidCoeff(fDstCoeff)); } virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE { diff --git a/src/effects/SkBicubicImageFilter.cpp b/src/effects/SkBicubicImageFilter.cpp index 0ffcde6e2e..b7dffb8bc8 100644 --- a/src/effects/SkBicubicImageFilter.cpp +++ b/src/effects/SkBicubicImageFilter.cpp @@ -45,6 +45,10 @@ SkBicubicImageFilter::SkBicubicImageFilter(SkFlattenableReadBuffer& buffer) : IN SkASSERT(readSize == 16); fScale.fWidth = buffer.readScalar(); fScale.fHeight = buffer.readScalar(); + buffer.validate(SkScalarIsFinite(fScale.fWidth) && + SkScalarIsFinite(fScale.fHeight) && + (fScale.fWidth >= 0) && + (fScale.fHeight >= 0)); } void SkBicubicImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const { diff --git a/src/effects/SkBlurImageFilter.cpp b/src/effects/SkBlurImageFilter.cpp index 3f97ddd59a..10f389095f 100644 --- a/src/effects/SkBlurImageFilter.cpp +++ b/src/effects/SkBlurImageFilter.cpp @@ -19,6 +19,10 @@ SkBlurImageFilter::SkBlurImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) { fSigma.fWidth = buffer.readScalar(); fSigma.fHeight = buffer.readScalar(); + buffer.validate(SkScalarIsFinite(fSigma.fWidth) && + SkScalarIsFinite(fSigma.fHeight) && + (fSigma.fWidth >= 0) && + (fSigma.fHeight >= 0)); } SkBlurImageFilter::SkBlurImageFilter(SkScalar sigmaX, diff --git a/src/effects/SkColorFilters.cpp b/src/effects/SkColorFilters.cpp index 41a201ef39..7373f004d5 100644 --- a/src/effects/SkColorFilters.cpp +++ b/src/effects/SkColorFilters.cpp @@ -13,6 +13,7 @@ #include "SkFlattenableBuffers.h" #include "SkUtils.h" #include "SkString.h" +#include "SkValidationUtils.h" #define ILLEGAL_XFERMODE_MODE ((SkXfermode::Mode)-1) @@ -98,6 +99,7 @@ protected: fColor = buffer.readColor(); fMode = (SkXfermode::Mode)buffer.readUInt(); this->updateCache(); + buffer.validate(SkIsValidMode(fMode)); } private: diff --git a/src/effects/SkColorMatrixFilter.cpp b/src/effects/SkColorMatrixFilter.cpp index 1f841d0489..842d372296 100644 --- a/src/effects/SkColorMatrixFilter.cpp +++ b/src/effects/SkColorMatrixFilter.cpp @@ -310,6 +310,9 @@ SkColorMatrixFilter::SkColorMatrixFilter(SkFlattenableReadBuffer& buffer) SkASSERT(buffer.getArrayCount() == 20); buffer.readScalarArray(fMatrix.fMat); this->initState(fMatrix.fMat); + for (int i = 0; i < 20; ++i) { + buffer.validate(SkScalarIsFinite(fMatrix.fMat[0])); + } } bool SkColorMatrixFilter::asColorMatrix(SkScalar matrix[20]) const { diff --git a/src/effects/SkDisplacementMapEffect.cpp b/src/effects/SkDisplacementMapEffect.cpp index a751365b75..11bd567c7c 100644 --- a/src/effects/SkDisplacementMapEffect.cpp +++ b/src/effects/SkDisplacementMapEffect.cpp @@ -128,6 +128,20 @@ void computeDisplacement(SkDisplacementMapEffect::ChannelSelectorType xChannelSe } } +bool ChannelSelectorTypeIsValid(SkDisplacementMapEffect::ChannelSelectorType channelSelector) { + switch (channelSelector) { + case SkDisplacementMapEffect::kUnknown_ChannelSelectorType: + case SkDisplacementMapEffect::kR_ChannelSelectorType: + case SkDisplacementMapEffect::kG_ChannelSelectorType: + case SkDisplacementMapEffect::kB_ChannelSelectorType: + case SkDisplacementMapEffect::kA_ChannelSelectorType: + return true; + default: + break; + } + return false; +} + } // end namespace /////////////////////////////////////////////////////////////////////////////// @@ -153,6 +167,9 @@ SkDisplacementMapEffect::SkDisplacementMapEffect(SkFlattenableReadBuffer& buffer fXChannelSelector = (SkDisplacementMapEffect::ChannelSelectorType) buffer.readInt(); fYChannelSelector = (SkDisplacementMapEffect::ChannelSelectorType) buffer.readInt(); fScale = buffer.readScalar(); + buffer.validate(ChannelSelectorTypeIsValid(fXChannelSelector) && + ChannelSelectorTypeIsValid(fYChannelSelector) && + SkScalarIsFinite(fScale)); } void SkDisplacementMapEffect::flatten(SkFlattenableWriteBuffer& buffer) const { diff --git a/src/effects/SkDropShadowImageFilter.cpp b/src/effects/SkDropShadowImageFilter.cpp index 75a86689c0..4fc29bae83 100644 --- a/src/effects/SkDropShadowImageFilter.cpp +++ b/src/effects/SkDropShadowImageFilter.cpp @@ -29,6 +29,9 @@ SkDropShadowImageFilter::SkDropShadowImageFilter(SkFlattenableReadBuffer& buffer fDy = buffer.readScalar(); fSigma = buffer.readScalar(); fColor = buffer.readColor(); + buffer.validate(SkScalarIsFinite(fDx) && + SkScalarIsFinite(fDy) && + SkScalarIsFinite(fSigma)); } void SkDropShadowImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp index ecf9913d2a..5460559aac 100644 --- a/src/effects/SkLightingImageFilter.cpp +++ b/src/effects/SkLightingImageFilter.cpp @@ -249,6 +249,9 @@ SkPoint3 readPoint3(SkFlattenableReadBuffer& buffer) { point.fX = buffer.readScalar(); point.fY = buffer.readScalar(); point.fZ = buffer.readScalar(); + buffer.validate(SkScalarIsFinite(point.fX) && + SkScalarIsFinite(point.fY) && + SkScalarIsFinite(point.fZ)); return point; }; @@ -741,6 +744,10 @@ protected: fCosInnerConeAngle = buffer.readScalar(); fConeScale = buffer.readScalar(); fS = readPoint3(buffer); + buffer.validate(SkScalarIsFinite(fSpecularExponent) && + SkScalarIsFinite(fCosOuterConeAngle) && + SkScalarIsFinite(fCosInnerConeAngle) && + SkScalarIsFinite(fConeScale)); } SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cosOuterConeAngle, SkScalar cosInnerConeAngle, SkScalar coneScale, const SkPoint3& s, const SkPoint3& color) : INHERITED(color), @@ -862,6 +869,7 @@ SkLightingImageFilter::SkLightingImageFilter(SkFlattenableReadBuffer& buffer) { fLight = buffer.readFlattenableT(); fSurfaceScale = buffer.readScalar(); + buffer.validate(SkScalarIsFinite(fSurfaceScale)); } void SkLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const { @@ -882,6 +890,7 @@ SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkFlattenableReadBuff : INHERITED(buffer) { fKD = buffer.readScalar(); + buffer.validate(SkScalarIsFinite(fKD)); } void SkDiffuseLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const { @@ -959,6 +968,8 @@ SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkFlattenableReadBu { fKS = buffer.readScalar(); fShininess = buffer.readScalar(); + buffer.validate(SkScalarIsFinite(fKS) && + SkScalarIsFinite(fShininess)); } void SkSpecularLightingImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const { diff --git a/src/effects/SkMagnifierImageFilter.cpp b/src/effects/SkMagnifierImageFilter.cpp index c74b067267..3edd490b3a 100644 --- a/src/effects/SkMagnifierImageFilter.cpp +++ b/src/effects/SkMagnifierImageFilter.cpp @@ -9,6 +9,7 @@ #include "SkMagnifierImageFilter.h" #include "SkColorPriv.h" #include "SkFlattenableBuffers.h" +#include "SkValidationUtils.h" //////////////////////////////////////////////////////////////////////////////// #if SK_SUPPORT_GPU @@ -252,6 +253,8 @@ SkMagnifierImageFilter::SkMagnifierImageFilter(SkFlattenableReadBuffer& buffer) float height = buffer.readScalar(); fSrcRect = SkRect::MakeXYWH(x, y, width, height); fInset = buffer.readScalar(); + + buffer.validate(SkIsValidRect(fSrcRect) && SkScalarIsFinite(fInset)); } // FIXME: implement single-input semantics diff --git a/src/effects/SkMatrixConvolutionImageFilter.cpp b/src/effects/SkMatrixConvolutionImageFilter.cpp index 9446b8ee19..dab890f01a 100644 --- a/src/effects/SkMatrixConvolutionImageFilter.cpp +++ b/src/effects/SkMatrixConvolutionImageFilter.cpp @@ -22,6 +22,22 @@ #endif +namespace { + +bool TileModeIsValid(SkMatrixConvolutionImageFilter::TileMode tileMode) { + switch (tileMode) { + case SkMatrixConvolutionImageFilter::kClamp_TileMode: + case SkMatrixConvolutionImageFilter::kRepeat_TileMode: + case SkMatrixConvolutionImageFilter::kClampToBlack_TileMode: + return true; + default: + break; + } + return false; +} + +} + SkMatrixConvolutionImageFilter::SkMatrixConvolutionImageFilter(const SkISize& kernelSize, const SkScalar* kernel, SkScalar gain, SkScalar bias, const SkIPoint& target, TileMode tileMode, bool convolveAlpha, SkImageFilter* input) : INHERITED(input), fKernelSize(kernelSize), @@ -51,6 +67,9 @@ SkMatrixConvolutionImageFilter::SkMatrixConvolutionImageFilter(SkFlattenableRead fTarget.fY = buffer.readInt(); fTileMode = (TileMode) buffer.readInt(); fConvolveAlpha = buffer.readBool(); + buffer.validate(SkScalarIsFinite(fGain) && + SkScalarIsFinite(fBias) && + TileModeIsValid(fTileMode)); } void SkMatrixConvolutionImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const { diff --git a/src/effects/SkMergeImageFilter.cpp b/src/effects/SkMergeImageFilter.cpp index 0c47c91aff..06040fdd40 100755 --- a/src/effects/SkMergeImageFilter.cpp +++ b/src/effects/SkMergeImageFilter.cpp @@ -9,6 +9,7 @@ #include "SkCanvas.h" #include "SkDevice.h" #include "SkFlattenableBuffers.h" +#include "SkValidationUtils.h" /////////////////////////////////////////////////////////////////////////////// @@ -157,8 +158,12 @@ SkMergeImageFilter::SkMergeImageFilter(SkFlattenableReadBuffer& buffer) : INHERI bool hasModes = buffer.readBool(); if (hasModes) { this->initAllocModes(); - SkASSERT(buffer.getArrayCount() == countInputs() * sizeof(fModes[0])); + int nbInputs = countInputs(); + SkASSERT(buffer.getArrayCount() == nbInputs * sizeof(fModes[0])); buffer.readByteArray(fModes); + for (int i = 0; i < nbInputs; ++i) { + buffer.validate(SkIsValidMode((SkXfermode::Mode)fModes[i])); + } } else { fModes = 0; } diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp index 83157bef6e..ecc8074b0c 100644 --- a/src/effects/SkMorphologyImageFilter.cpp +++ b/src/effects/SkMorphologyImageFilter.cpp @@ -24,6 +24,10 @@ SkMorphologyImageFilter::SkMorphologyImageFilter(SkFlattenableReadBuffer& buffer : INHERITED(buffer) { fRadius.fWidth = buffer.readInt(); fRadius.fHeight = buffer.readInt(); + buffer.validate(SkScalarIsFinite(fRadius.fWidth) && + SkScalarIsFinite(fRadius.fHeight) && + (fRadius.fWidth >= 0) && + (fRadius.fHeight >= 0)); } SkMorphologyImageFilter::SkMorphologyImageFilter(int radiusX, int radiusY, SkImageFilter* input) diff --git a/src/effects/SkOffsetImageFilter.cpp b/src/effects/SkOffsetImageFilter.cpp index ad5e49d776..2246537ac4 100644 --- a/src/effects/SkOffsetImageFilter.cpp +++ b/src/effects/SkOffsetImageFilter.cpp @@ -50,4 +50,6 @@ SkOffsetImageFilter::SkOffsetImageFilter(SkScalar dx, SkScalar dy, SkOffsetImageFilter::SkOffsetImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) { buffer.readPoint(&fOffset); + buffer.validate(SkScalarIsFinite(fOffset.fX) && + SkScalarIsFinite(fOffset.fY)); } diff --git a/src/effects/SkRectShaderImageFilter.cpp b/src/effects/SkRectShaderImageFilter.cpp index 2ee1d4a2ed..3099ad442a 100644 --- a/src/effects/SkRectShaderImageFilter.cpp +++ b/src/effects/SkRectShaderImageFilter.cpp @@ -11,6 +11,7 @@ #include "SkDevice.h" #include "SkFlattenableBuffers.h" #include "SkShader.h" +#include "SkValidationUtils.h" SkRectShaderImageFilter* SkRectShaderImageFilter::Create(SkShader* s, const SkRect& rect) { SkASSERT(s); @@ -29,6 +30,7 @@ SkRectShaderImageFilter::SkRectShaderImageFilter(SkFlattenableReadBuffer& buffer : INHERITED(buffer) { fShader = buffer.readFlattenableT(); buffer.readRect(&fRect); + buffer.validate(SkIsValidRect(fRect)); } void SkRectShaderImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const { diff --git a/src/effects/SkTestImageFilters.cpp b/src/effects/SkTestImageFilters.cpp index 788c33a411..d0e21a3920 100755 --- a/src/effects/SkTestImageFilters.cpp +++ b/src/effects/SkTestImageFilters.cpp @@ -78,4 +78,5 @@ void SkDownSampleImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const { SkDownSampleImageFilter::SkDownSampleImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) { fScale = buffer.readScalar(); + buffer.validate(SkScalarIsFinite(fScale)); }