diff options
author | Kevin Lubick <kjlubick@users.noreply.github.com> | 2018-01-23 15:28:11 -0500 |
---|---|---|
committer | jonathanmetzman <31354670+jonathanmetzman@users.noreply.github.com> | 2018-01-23 12:28:11 -0800 |
commit | 5b7b48d7678084f1e27d4c9f5abb71e32ebe27f0 (patch) | |
tree | 52d924dff7bcd0edf1a09c37c6ed5b1115f4ff4c /projects | |
parent | 4e8526e38c40ff7ee038c1d20536045fcda4f5a2 (diff) |
First try at filter_fuzz in oss-fuzz (#1103)
Try to prevent ooms and timeouts. Use a seed corpus hosted in cloud storage.
Diffstat (limited to 'projects')
-rw-r--r-- | projects/skia/BUILD.gn.diff | 10 | ||||
-rw-r--r-- | projects/skia/Dockerfile | 9 | ||||
-rw-r--r-- | projects/skia/README.md | 1 | ||||
-rw-r--r-- | projects/skia/build.sh | 7 | ||||
-rw-r--r-- | projects/skia/image_filter_deserialize.cpp | 47 | ||||
-rw-r--r-- | projects/skia/image_filter_deserialize.options | 3 | ||||
-rw-r--r-- | projects/skia/skia.diff | 293 |
7 files changed, 367 insertions, 3 deletions
diff --git a/projects/skia/BUILD.gn.diff b/projects/skia/BUILD.gn.diff index 8017cdef..e868cb51 100644 --- a/projects/skia/BUILD.gn.diff +++ b/projects/skia/BUILD.gn.diff @@ -23,4 +23,14 @@ test_app("fuzz_region_deserialize") { ":flags", ":skia", ] +} + +test_app("image_filter_deserialize") { + sources = [ + "fuzz/oss_fuzz/image_filter_deserialize.cpp", + ] + deps = [ + ":flags", + ":skia", + ] }
\ No newline at end of file diff --git a/projects/skia/Dockerfile b/projects/skia/Dockerfile index 3daa1712..71f1c89d 100644 --- a/projects/skia/Dockerfile +++ b/projects/skia/Dockerfile @@ -17,7 +17,7 @@ FROM gcr.io/oss-fuzz-base/base-builder MAINTAINER kjlubick@chromium.org -RUN apt-get update && apt-get install -y python +RUN apt-get update && apt-get install -y python wget RUN git clone 'https://chromium.googlesource.com/chromium/tools/depot_tools.git' ENV PATH="${SRC}/depot_tools:${PATH}" @@ -32,6 +32,13 @@ RUN python tools/git-sync-deps COPY build.sh $SRC/ +COPY skia.diff $SRC/skia/skia.diff +RUN git apply skia.diff + COPY region_deserialize.options $SRC/skia/region_deserialize.options COPY BUILD.gn.diff $SRC/skia/BUILD.gn.diff RUN cat BUILD.gn.diff >> BUILD.gn + +COPY image_filter_deserialize.options $SRC/skia/image_filter_deserialize.options +RUN wget -O $SRC/skia/image_filter_deserialize_seed_corpus.zip https://storage.googleapis.com/skia-fuzzer/oss-fuzz/image_filter_deserialize_seed_corpus.zip +COPY image_filter_deserialize.cpp $SRC/skia/fuzz/oss_fuzz/image_filter_deserialize.cpp diff --git a/projects/skia/README.md b/projects/skia/README.md new file mode 100644 index 00000000..36b3629c --- /dev/null +++ b/projects/skia/README.md @@ -0,0 +1 @@ +When bench testing image_filter_deserialize, it may be useful to have malloc_limit_mb = 500, and timeout = 10 to find actionalbe OOM culprits sooner.
\ No newline at end of file diff --git a/projects/skia/build.sh b/projects/skia/build.sh index 7dbdd378..2bfeb483 100644 --- a/projects/skia/build.sh +++ b/projects/skia/build.sh @@ -25,15 +25,18 @@ $SRC/depot_tools/gn gen out/Fuzz\ --args='cc="'$CC'" cxx="'$CXX'" is_debug=false - extra_cflags=["'"$CXXFLAGS_ARR"'","-DIS_FUZZING_WITH_LIBFUZZER", + extra_cflags=["'"$CXXFLAGS_ARR"'","-DIS_FUZZING","-DIS_FUZZING_WITH_LIBFUZZER", "-Wno-zero-as-null-pointer-constant", "-Wno-unused-template", "-Wno-cast-qual"] skia_use_system_freetype2=false skia_use_fontconfig=false skia_enable_gpu=false extra_ldflags=["-lFuzzingEngine", "'"$CXXFLAGS_ARR"'"]' -$SRC/depot_tools/ninja -C out/Fuzz fuzz_region_deserialize +$SRC/depot_tools/ninja -C out/Fuzz fuzz_region_deserialize image_filter_deserialize cp out/Fuzz/fuzz_region_deserialize $OUT/region_deserialize cp ./region_deserialize.options $OUT/region_deserialize.options +cp out/Fuzz/image_filter_deserialize $OUT/image_filter_deserialize +cp ./image_filter_deserialize.options $OUT/image_filter_deserialize.options +cp ./image_filter_deserialize_seed_corpus.zip $OUT/image_filter_deserialize_seed_corpus.zip diff --git a/projects/skia/image_filter_deserialize.cpp b/projects/skia/image_filter_deserialize.cpp new file mode 100644 index 00000000..1ae73354 --- /dev/null +++ b/projects/skia/image_filter_deserialize.cpp @@ -0,0 +1,47 @@ +// Copyright 2018 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// TODO(kjlubick): Move this into Skia proper + + +#include "SkCanvas.h" +#include "SkBitmap.h" +#include "SkImageFilter.h" +#include "SkPaint.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + const int BitmapSize = 24; + SkBitmap bitmap; + bitmap.allocN32Pixels(BitmapSize, BitmapSize); + SkCanvas canvas(bitmap); + canvas.clear(0x00000000); + + auto flattenable = SkImageFilter::Deserialize(data, size); + + if (flattenable != nullptr) { + // Let's see if using the filters can cause any trouble... + SkPaint paint; + paint.setImageFilter(flattenable); + canvas.save(); + canvas.clipRect(SkRect::MakeXYWH( + 0, 0, SkIntToScalar(BitmapSize), SkIntToScalar(BitmapSize))); + + // This call shouldn't crash or cause ASAN to flag any memory issues + // If nothing bad happens within this call, everything is fine + canvas.drawBitmap(bitmap, 0, 0, &paint); + + canvas.restore(); + } + return 0; // Non-zero return values are reserved for future use. +}
\ No newline at end of file diff --git a/projects/skia/image_filter_deserialize.options b/projects/skia/image_filter_deserialize.options new file mode 100644 index 00000000..05ba1b17 --- /dev/null +++ b/projects/skia/image_filter_deserialize.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 10024 +timeout = 10
\ No newline at end of file diff --git a/projects/skia/skia.diff b/projects/skia/skia.diff new file mode 100644 index 00000000..2c75a957 --- /dev/null +++ b/projects/skia/skia.diff @@ -0,0 +1,293 @@ +diff --git a/include/private/SkMalloc.h b/include/private/SkMalloc.h +index 178e1b83a7..d06dc3a4c2 100644 +--- a/include/private/SkMalloc.h ++++ b/include/private/SkMalloc.h +@@ -64,6 +64,11 @@ static inline void* sk_calloc_throw(size_t size) { + } + + static inline void* sk_calloc_canfail(size_t size) { ++#if defined(IS_FUZZING) ++ if (size > 100000) { ++ return nullptr; ++ } ++#endif + return sk_malloc_flags(size, SK_MALLOC_ZERO_INITIALIZE); + } + +@@ -76,6 +81,11 @@ SK_API extern void* sk_realloc_throw(void* buffer, size_t count, size_t elemSize + * These variants return nullptr on failure + */ + static inline void* sk_malloc_canfail(size_t size) { ++#if defined(IS_FUZZING) ++ if (size > 100000) { ++ return nullptr; ++ } ++#endif + return sk_malloc_flags(size, 0); + } + SK_API extern void* sk_malloc_canfail(size_t count, size_t elemSize); +diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp +index e5ba0eb09f..163ade217d 100644 +--- a/src/core/SkImageFilter.cpp ++++ b/src/core/SkImageFilter.cpp +@@ -123,6 +123,12 @@ bool SkImageFilter::Common::unflatten(SkReadBuffer& buffer, int expectedCount) { + return false; + } + ++#if defined(IS_FUZZING) ++ if (count > 4) { ++ return false; ++ } ++#endif ++ + this->allocInputs(count); + for (int i = 0; i < count; i++) { + if (buffer.readBool()) { +diff --git a/src/core/SkMallocPixelRef.cpp b/src/core/SkMallocPixelRef.cpp +index 2933e48cc4..1ae9dd0404 100644 +--- a/src/core/SkMallocPixelRef.cpp ++++ b/src/core/SkMallocPixelRef.cpp +@@ -73,6 +73,11 @@ sk_sp<SkPixelRef> SkMallocPixelRef::MakeUsing(void*(*allocProc)(size_t), + return nullptr; + } + } ++#if defined(IS_FUZZING) ++ if (size > 100000) { ++ return nullptr; ++ } ++#endif + void* addr = allocProc(size); + if (nullptr == addr) { + return nullptr; +diff --git a/src/core/SkMaskFilter.cpp b/src/core/SkMaskFilter.cpp +index 75d29e12a8..5157f6dcb3 100644 +--- a/src/core/SkMaskFilter.cpp ++++ b/src/core/SkMaskFilter.cpp +@@ -260,6 +260,11 @@ bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix, + + SkMask srcM, dstM; + ++#if defined(IS_FUZZING) ++ if (devPath.countVerbs() > 1000 || devPath.countPoints() > 1000) { ++ return false; ++ } ++#endif + if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), this, &matrix, &srcM, + SkMask::kComputeBoundsAndRenderImage_CreateMode, + style)) { +diff --git a/src/core/SkPictureData.cpp b/src/core/SkPictureData.cpp +index 0d729f8a75..932c016d43 100644 +--- a/src/core/SkPictureData.cpp ++++ b/src/core/SkPictureData.cpp +@@ -497,6 +497,11 @@ bool new_array_from_buffer(SkReadBuffer& buffer, uint32_t inCount, + } + + bool SkPictureData::parseBufferTag(SkReadBuffer& buffer, uint32_t tag, uint32_t size) { ++#if defined(IS_FUZZING) ++ if (size > 1000) { ++ return false; ++ } ++#endif + switch (tag) { + case SK_PICT_PAINT_BUFFER_TAG: { + if (!buffer.validate(SkTFitsIn<int>(size))) { +@@ -516,6 +521,11 @@ bool SkPictureData::parseBufferTag(SkReadBuffer& buffer, uint32_t tag, uint32_t + if (count < 0) { + return false; + } ++ #if defined(IS_FUZZING) ++ if (count > 20) { ++ return false; ++ } ++ #endif + fPaths.reset(count); + for (int i = 0; i < count; i++) { + buffer.readPath(&fPaths[i]); +diff --git a/src/core/SkReadBuffer.cpp b/src/core/SkReadBuffer.cpp +index 8da4089a17..bf2a997420 100644 +--- a/src/core/SkReadBuffer.cpp ++++ b/src/core/SkReadBuffer.cpp +@@ -256,7 +256,12 @@ bool SkReadBuffer::readScalarArray(SkScalar* values, size_t size) { + uint32_t SkReadBuffer::getArrayCount() { + const size_t inc = sizeof(uint32_t); + fError = fError || !IsPtrAlign4(fReader.peek()) || !fReader.isAvailable(inc); ++#if defined(IS_FUZZING) ++ uint32_t retVal = fError ? 0 : *(uint32_t*)fReader.peek(); ++ return retVal < 1000 ? retVal: 1000; ++#else + return fError ? 0 : *(uint32_t*)fReader.peek(); ++#endif + } + + sk_sp<SkImage> SkReadBuffer::readImage() { +@@ -291,6 +296,12 @@ sk_sp<SkImage> SkReadBuffer::readImage() { + } + + size_t size = SkAbs32(encoded_size); ++#if defined(IS_FUZZING) ++ if (size > 100000) { ++ this->validate(false); ++ return nullptr; ++ } ++#endif + sk_sp<SkData> data = SkData::MakeUninitialized(size); + if (!this->readPad32(data->writable_data(), size)) { + this->validate(false); +diff --git a/src/core/SkScan_Path.cpp b/src/core/SkScan_Path.cpp +index f2a18b631e..39f8ecb2ce 100644 +--- a/src/core/SkScan_Path.cpp ++++ b/src/core/SkScan_Path.cpp +@@ -253,6 +253,11 @@ static void walk_convex_edges(SkEdge* prevHead, SkPath::FillType, + } + local_top = local_bot + 1; + } else { ++#if defined(IS_FUZZING) ++ if (count > 1000) { ++ count = 1000; ++ } ++#endif + do { + int L = SkFixedRoundToInt(left); + int R = SkFixedRoundToInt(rite); +diff --git a/src/core/SkTextBlob.cpp b/src/core/SkTextBlob.cpp +index 6d89e6f135..680534d384 100644 +--- a/src/core/SkTextBlob.cpp ++++ b/src/core/SkTextBlob.cpp +@@ -800,7 +800,11 @@ sk_sp<SkTextBlob> SkTextBlob::MakeFromBuffer(SkReadBuffer& reader) { + // End-of-runs marker. + break; + } +- ++#if defined(IS_FUZZING) ++ if (glyphCount > 1000) { ++ return nullptr; ++ } ++#endif + PositioningAndExtended pe; + pe.intValue = reader.read32(); + GlyphPositioning pos = pe.positioning; +@@ -811,7 +815,11 @@ sk_sp<SkTextBlob> SkTextBlob::MakeFromBuffer(SkReadBuffer& reader) { + if (textSize < 0) { + return nullptr; + } +- ++#if defined(IS_FUZZING) ++ if (textSize > 1000) { ++ return nullptr; ++ } ++#endif + SkPoint offset; + reader.readPoint(&offset); + SkPaint font; +diff --git a/src/effects/Sk1DPathEffect.cpp b/src/effects/Sk1DPathEffect.cpp +index 37cd13052e..5ef2e0c4b8 100644 +--- a/src/effects/Sk1DPathEffect.cpp ++++ b/src/effects/Sk1DPathEffect.cpp +@@ -15,6 +15,11 @@ + bool Sk1DPathEffect::filterPath(SkPath* dst, const SkPath& src, + SkStrokeRec*, const SkRect*) const { + SkPathMeasure meas(src, false); ++#if defined(IS_FUZZING) ++ if (meas.getLength() < 0 || meas.getLength() > 100) { ++ return false; ++ } ++#endif + do { + SkScalar length = meas.getLength(); + SkScalar distance = this->begin(length); +@@ -23,6 +28,11 @@ bool Sk1DPathEffect::filterPath(SkPath* dst, const SkPath& src, + if (delta <= 0) { + break; + } ++#if defined(IS_FUZZING) ++ if (delta <= SK_ScalarNearlyZero) { ++ return false; ++ } ++#endif + distance += delta; + } + } while (meas.nextContour()); +@@ -65,6 +75,11 @@ SkPath1DPathEffect::SkPath1DPathEffect(const SkPath& path, SkScalar advance, + + bool SkPath1DPathEffect::filterPath(SkPath* dst, const SkPath& src, + SkStrokeRec* rec, const SkRect* cullRect) const { ++#if defined(IS_FUZZING) ++ if (dst->countVerbs() > 100 || dst->countPoints() > 100) { ++ return false; ++ } ++#endif + if (fAdvance > 0) { + rec->setFillStyle(); + return this->INHERITED::filterPath(dst, src, rec, cullRect); +@@ -109,6 +124,7 @@ static void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas, + SkPoint srcP[4], dstP[3]; + SkPath::Verb verb; + ++ //SkDebugf("morphpath Measure %d\n", meas.getLength()); + while ((verb = iter.next(srcP)) != SkPath::kDone_Verb) { + switch (verb) { + case SkPath::kMove_Verb: +diff --git a/src/effects/Sk2DPathEffect.cpp b/src/effects/Sk2DPathEffect.cpp +index e7ef54b6f7..727aa5221f 100644 +--- a/src/effects/Sk2DPathEffect.cpp ++++ b/src/effects/Sk2DPathEffect.cpp +@@ -51,6 +51,11 @@ void Sk2DPathEffect::nextSpan(int x, int y, int count, SkPath* path) const { + if (!fMatrixIsInvertible) { + return; + } ++#if defined(IS_FUZZING) ++ if (count > 100) { ++ return; ++ } ++#endif + + const SkMatrix& mat = this->getMatrix(); + SkPoint src, dst; +diff --git a/src/effects/SkDashPathEffect.cpp b/src/effects/SkDashPathEffect.cpp +index 04f9e9e85f..e6976d62d1 100644 +--- a/src/effects/SkDashPathEffect.cpp ++++ b/src/effects/SkDashPathEffect.cpp +@@ -367,6 +367,11 @@ void SkDashImpl::flatten(SkWriteBuffer& buffer) const { + sk_sp<SkFlattenable> SkDashImpl::CreateProc(SkReadBuffer& buffer) { + const SkScalar phase = buffer.readScalar(); + uint32_t count = buffer.getArrayCount(); ++#if defined(IS_FUZZING) ++ if (count > 20) { ++ return nullptr; ++ } ++#endif + SkAutoSTArray<32, SkScalar> intervals(count); + if (buffer.readScalarArray(intervals.get(), count)) { + return SkDashPathEffect::Make(intervals.get(), SkToInt(count), phase); +diff --git a/src/effects/SkLayerDrawLooper.cpp b/src/effects/SkLayerDrawLooper.cpp +index 7dff657c52..b09597f0a2 100644 +--- a/src/effects/SkLayerDrawLooper.cpp ++++ b/src/effects/SkLayerDrawLooper.cpp +@@ -261,6 +261,11 @@ void SkLayerDrawLooper::flatten(SkWriteBuffer& buffer) const { + sk_sp<SkFlattenable> SkLayerDrawLooper::CreateProc(SkReadBuffer& buffer) { + int count = buffer.readInt(); + ++#if defined(IS_FUZZING) ++ if (count > 100) { ++ count = 100; ++ } ++#endif + Builder builder; + for (int i = 0; i < count; i++) { + LayerInfo info; +diff --git a/src/utils/SkShadowTessellator.cpp b/src/utils/SkShadowTessellator.cpp +index 1a714076e7..18ef8d0235 100755 +--- a/src/utils/SkShadowTessellator.cpp ++++ b/src/utils/SkShadowTessellator.cpp +@@ -245,6 +245,11 @@ bool SkBaseShadowTessellator::addArc(const SkVector& nextNormal, bool finishArc) + SkScalar rotSin, rotCos; + int numSteps; + compute_radial_steps(fPrevOutset, nextNormal, fRadius, &rotSin, &rotCos, &numSteps); ++#if defined(IS_FUZZING) ++ if (numSteps > 50 || numSteps < 0) { ++ return false; ++ } ++#endif + SkVector prevNormal = fPrevOutset; + for (int i = 0; i < numSteps-1; ++i) { + SkVector currNormal; |