diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml new file mode 100644 index 00000000..850541a0 --- /dev/null +++ b/.github/workflows/cifuzz.yml @@ -0,0 +1,36 @@ +name: CIFuzz +on: [pull_request] +permissions: {} +jobs: + Fuzzing: + runs-on: ubuntu-latest + permissions: + security-events: write + steps: + - name: Build Fuzzers + id: build + uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master + with: + oss-fuzz-project-name: 'icalendar' + language: python + - name: Run Fuzzers + uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master + with: + oss-fuzz-project-name: 'icalendar' + language: python + fuzz-seconds: 600 + output-sarif: true + - name: Upload Crash + uses: actions/upload-artifact@v3 + if: failure() && steps.build.outcome == 'success' + with: + name: artifacts + path: ./out/artifacts + - name: Upload Sarif + if: always() && steps.build.outcome == 'success' + uses: github/codeql-action/upload-sarif@v2 + with: + # Path to SARIF file relative to the root of the repository + sarif_file: cifuzz-sarif/results.sarif + checkout_path: cifuzz-sarif + diff --git a/CHANGES.rst b/CHANGES.rst index d3816d2e..24e34ee9 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -16,6 +16,7 @@ Breaking changes: New features: +- Added fuzzing harnesses, for integration to OSSFuzz. - icalendar releases are deployed to Github releases Fixes: #563 [jacadzaca] diff --git a/src/icalendar/fuzzing/build.sh b/src/icalendar/fuzzing/build.sh new file mode 100755 index 00000000..09c317ce --- /dev/null +++ b/src/icalendar/fuzzing/build.sh @@ -0,0 +1,25 @@ +#!/bin/bash -eu +# Copyright 2023 Google LLC +# +# 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. +# +################################################################################ + +cd "$SRC"/icalendar +pip3 install . + +# Build fuzzers in $OUT +for fuzzer in $(find $SRC -name 'src/icalendar/fuzzing/*_fuzzer.py');do + compile_python_fuzzer "$fuzzer" +done +zip -q $OUT/ical_fuzzer_seed_corpus.zip $SRC/corpus/* diff --git a/src/icalendar/fuzzing/ical_fuzzer.py b/src/icalendar/fuzzing/ical_fuzzer.py new file mode 100644 index 00000000..d524920a --- /dev/null +++ b/src/icalendar/fuzzing/ical_fuzzer.py @@ -0,0 +1,47 @@ +#!/usr/bin/python3 +# Copyright 2023 Google LLC +# +# 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. +# +################################################################################ +import atheris +import sys + +with atheris.instrument_imports(include=['icalendar']): + from icalendar import Calendar + + +def TestOneInput(data): + fdp = atheris.FuzzedDataProvider(data) + try: + b = fdp.ConsumeBool() + + cal = Calendar.from_ical(fdp.ConsumeString(fdp.remaining_bytes())) + + if b: + for event in cal.walk('VEVENT'): + event.to_ical().decode('utf-8') + else: + cal.to_ical() + except ValueError as e: + if "component" in str(e) or "parse" in str(e) or "Expected" in str(e): + return -1 + raise e + +def main(): + atheris.Setup(sys.argv, TestOneInput) + atheris.Fuzz() + + +if __name__ == "__main__": + main() diff --git a/src/icalendar/tests/test_with_doctest.py b/src/icalendar/tests/test_with_doctest.py index 652198c3..d536ff9c 100644 --- a/src/icalendar/tests/test_with_doctest.py +++ b/src/icalendar/tests/test_with_doctest.py @@ -21,7 +21,7 @@ PYTHON_FILES = [ os.path.join(dirpath, filename) for dirpath, dirnames, filenames in os.walk(ICALENDAR_PATH) - for filename in filenames if filename.lower().endswith(".py") + for filename in filenames if filename.lower().endswith(".py") and 'fuzzing' not in dirpath ] MODULE_NAMES = [