aboutsummaryrefslogtreecommitdiffhomepage
path: root/projects
diff options
context:
space:
mode:
authorGravatar Kevin Lubick <kjlubick@users.noreply.github.com>2018-01-23 15:28:11 -0500
committerGravatar jonathanmetzman <31354670+jonathanmetzman@users.noreply.github.com>2018-01-23 12:28:11 -0800
commit5b7b48d7678084f1e27d4c9f5abb71e32ebe27f0 (patch)
tree52d924dff7bcd0edf1a09c37c6ed5b1115f4ff4c /projects
parent4e8526e38c40ff7ee038c1d20536045fcda4f5a2 (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.diff10
-rw-r--r--projects/skia/Dockerfile9
-rw-r--r--projects/skia/README.md1
-rw-r--r--projects/skia/build.sh7
-rw-r--r--projects/skia/image_filter_deserialize.cpp47
-rw-r--r--projects/skia/image_filter_deserialize.options3
-rw-r--r--projects/skia/skia.diff293
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;