Commit message: None
CVE: CVE-2018-9498
CWE: CWE-787
Vulnerability description: In SkSampler::Fill of SkSampler.cpp, there is a possible out of bounds write due to an integer overflow. This could lead to remote code execution with no additional execution privileges needed. User interaction is needed for exploitation. Product: Android Versions: Android-7.0 Android-7.1.1 Android-7.1.2 Android-8.0 Android-8.1 Android ID: A-78354855

Project: Android

bool SkIcoCodec::IsIco(const void* buffer, size_t bytesRead) {
 const char icoSig[] = { '\x00', '\x00', '\x01', '\x00' };
 const char curSig[] = { '\x00', '\x00', '\x02', '\x00' };
 return bytesRead >= sizeof(icoSig) &&
 (!memcmp(buffer, icoSig, sizeof(icoSig)) ||
 !memcmp(buffer, curSig, sizeof(curSig)));
}

Project: Android

SkIcoCodec::SkIcoCodec(int width, int height, const SkEncodedInfo& info,
 SkTArray<std::unique_ptr<SkCodec>, true>* codecs,
                       sk_sp<SkColorSpace> colorSpace)
 : INHERITED(width, height, info, SkColorSpaceXform::ColorFormat(), nullptr,
                std::move(colorSpace))
 , fEmbeddedCodecs(codecs)
 , fCurrScanlineCodec(nullptr)
 , fCurrIncrementalCodec(nullptr)
{}

Project: Android

int SkIcoCodec::chooseCodec(const SkISize& requestedSize, int startIndex) {
 SkASSERT(startIndex >= 0);

 for (int i = startIndex; i < fEmbeddedCodecs->count(); i++) {
 if (fEmbeddedCodecs->operator[](i)->getInfo().dimensions() == requestedSize) {
 return i;
 }
 }

 return -1;
}

Project: Android

SkSampler* SkIcoCodec::getSampler(bool createIfNecessary) {
 if (fCurrScanlineCodec) {
 SkASSERT(!fCurrIncrementalCodec);
 return fCurrScanlineCodec->getSampler(createIfNecessary);
 }

 if (fCurrIncrementalCodec) {
 return fCurrIncrementalCodec->getSampler(createIfNecessary);
 }

 return nullptr;
}

Project: Android

SkCodec::Result SkIcoCodec::onGetPixels(const SkImageInfo& dstInfo,
 void* dst, size_t dstRowBytes,
 const Options& opts,
 int* rowsDecoded) {
 if (opts.fSubset) {
 return kUnimplemented;
 }

 int index = 0;
 SkCodec::Result result = kInvalidScale;
 while (true) {
        index = this->chooseCodec(dstInfo.dimensions(), index);
 if (index < 0) {
 break;
 }

 SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index).get();
        result = embeddedCodec->getPixels(dstInfo, dst, dstRowBytes, &opts);
 switch (result) {
 case kSuccess:
 case kIncompleteInput:
 *rowsDecoded = dstInfo.height();
 return result;
 default:
 break;
 }

        index++;
 }

 SkCodecPrintf("Error: No matching candidate image in ico.\n");
 return result;
}

Project: Android

int SkIcoCodec::onGetScanlines(void* dst, int count, size_t rowBytes) {
 SkASSERT(fCurrScanlineCodec);
 return fCurrScanlineCodec->getScanlines(dst, count, rowBytes);
}

Project: Android

SkCodec::Result SkIcoCodec::onIncrementalDecode(int* rowsDecoded) {
 SkASSERT(fCurrIncrementalCodec);
 return fCurrIncrementalCodec->incrementalDecode(rowsDecoded);
}

Project: Android

SkCodec::Result SkIcoCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
 const SkCodec::Options& options) {
 int index = 0;
 SkCodec::Result result = kInvalidScale;
 while (true) {
        index = this->chooseCodec(dstInfo.dimensions(), index);
 if (index < 0) {
 break;
 }

 SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index).get();
        result = embeddedCodec->startScanlineDecode(dstInfo, &options);
 if (kSuccess == result) {
            fCurrScanlineCodec = embeddedCodec;
            fCurrIncrementalCodec = nullptr;
 return result;
 }

        index++;
 }

 SkCodecPrintf("Error: No matching candidate image in ico.\n");
 return result;
}