diff --git a/projects/openh264/Dockerfile b/projects/openh264/Dockerfile new file mode 100644 index 000000000..eef2b15e7 --- /dev/null +++ b/projects/openh264/Dockerfile @@ -0,0 +1,22 @@ +# 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. +# +################################################################################ + +FROM gcr.io/oss-fuzz-base/base-builder +MAINTAINER twsmith@mozilla.com +RUN apt-get update && apt-get install -y libstdc++-5-dev +RUN git clone --depth 1 https://github.com/cisco/openh264.git openh264 +WORKDIR openh264 +COPY build.sh decoder_fuzzer.cpp $SRC/ diff --git a/projects/openh264/build.sh b/projects/openh264/build.sh new file mode 100755 index 000000000..22b34ad2e --- /dev/null +++ b/projects/openh264/build.sh @@ -0,0 +1,23 @@ +#!/bin/bash -eu +# 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. +# +################################################################################ + +# prepare corpus +zip -q0r ${OUT}/decoder_fuzzer_seed_corpus.zip ./res/ + +# build +make -j$(nproc) USE_ASM=No BUILDTYPE=Debug libraries +$CXX $CXXFLAGS -o $OUT/decoder_fuzzer -I./codec/api/svc -I./codec/console/common/inc -I./codec/common/inc -L. -lFuzzingEngine $SRC/decoder_fuzzer.cpp libopenh264.a diff --git a/projects/openh264/decoder_fuzzer.cpp b/projects/openh264/decoder_fuzzer.cpp new file mode 100644 index 000000000..2d5abb74c --- /dev/null +++ b/projects/openh264/decoder_fuzzer.cpp @@ -0,0 +1,82 @@ +// TODO: This should be moved to the openh264 repo. + +#include +#include +#include +#include +#include + +#include + +#include "codec_def.h" +#include "codec_app_def.h" +#include "codec_api.h" +#include "read_config.h" +#include "typedefs.h" +#include "measure_time.h" + +/* + * To build locally: + * CC=clang CXX=clang++ CFLAGS="-fsanitize=address,fuzzer-no-link -g" CXXFLAGS="-fsanitize=address,fuzzer-no-link -g" LDFLAGS="-fsanitize=address,fuzzer-no-link" make -j$(nproc) USE_ASM=No BUILDTYPE=Debug libraries + * clang++ -o decoder_fuzzer -fsanitize=address -g -O1 -I./codec/api/svc -I./codec/console/common/inc -I./codec/common/inc -L. -lFuzzer -lstdc++ decoder_fuzzer.cpp libopenh264.a + */ + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + int32_t i; + int32_t iBufPos = 0; + int32_t iEndOfStreamFlag; + int32_t iSliceSize; + ISVCDecoder *pDecoder; + SDecodingParam sDecParam = {0}; + SBufferInfo sDstBufInfo; + std::unique_ptr pBuf(new uint8_t[size + 4]); + uint8_t* pData[3] = {NULL}; + uint8_t uiStartCode[4] = {0, 0, 0, 1}; + + memcpy(pBuf.get(), data, size); + memcpy(pBuf.get() + size, &uiStartCode[0], 4); + memset(&sDstBufInfo, 0, sizeof(SBufferInfo)); + + // TODO: is this the best/fastest ERROR_CON to use? + sDecParam.eEcActiveIdc = ERROR_CON_SLICE_COPY; + // TODO: should we also fuzz VIDEO_BITSTREAM_SVC + sDecParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_AVC; + + WelsCreateDecoder (&pDecoder); + pDecoder->Initialize (&sDecParam); + + while (1) { + if (iBufPos >= size) { + iEndOfStreamFlag = 1; + if (iEndOfStreamFlag) + pDecoder->SetOption (DECODER_OPTION_END_OF_STREAM, (void*)&iEndOfStreamFlag); + break; + } + + for (i = 0; i < size; i++) { + if ((pBuf[iBufPos + i] == 0 && pBuf[iBufPos + i + 1] == 0 && pBuf[iBufPos + i + 2] == 0 && pBuf[iBufPos + i + 3] == 1 + && i > 0) || (pBuf[iBufPos + i] == 0 && pBuf[iBufPos + i + 1] == 0 && pBuf[iBufPos + i + 2] == 1 && i > 0)) { + break; + } + } + iSliceSize = i; + if (iSliceSize < 4) { + if (iSliceSize == 0) { + // I don't think this should happen but let's just avoid the hang + goto label_cleanup; + } + iBufPos += iSliceSize; + continue; + } + + pDecoder->DecodeFrameNoDelay (pBuf.get() + iBufPos, iSliceSize, pData, &sDstBufInfo); + iBufPos += iSliceSize; + } + +label_cleanup: + pDecoder->Uninitialize (); + WelsDestroyDecoder (pDecoder); + + return 0; +} diff --git a/projects/openh264/project.yaml b/projects/openh264/project.yaml new file mode 100644 index 000000000..6e829b644 --- /dev/null +++ b/projects/openh264/project.yaml @@ -0,0 +1,8 @@ +homepage: "https://www.openh264.org" +primary_contact: "huili2@cisco.com" +auto_ccs: + - "twsmith@mozilla.com" +sanitizers: + - address + - memory + - undefined