diff --git a/.clusterfuzzlite/Dockerfile b/.clusterfuzzlite/Dockerfile new file mode 100644 index 0000000..37a439f --- /dev/null +++ b/.clusterfuzzlite/Dockerfile @@ -0,0 +1,5 @@ +FROM gcr.io/oss-fuzz-base/base-builder-python:v1 +RUN apt-get update && apt-get install -y make autoconf automake libtool +COPY . $SRC/metis +WORKDIR metis +COPY .clusterfuzzlite/build.sh $SRC/ diff --git a/.clusterfuzzlite/build.sh b/.clusterfuzzlite/build.sh new file mode 100755 index 0000000..7992ec0 --- /dev/null +++ b/.clusterfuzzlite/build.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -eux + +export PIP_IGNORE_REQUIRES_PYTHON=1 +pip3 install --ignore-requires-python . + +cd "$(dirname "$0")"/.. + +find tests/fuzzing -type f -name '*_fuzzer.py' | while read -r fuzzer; do + name=$(basename -s .py "$fuzzer") + pkg="${name}.pkg" + + pyinstaller --distpath "$OUT" --onefile --name "$pkg" "$fuzzer" + + cat > "$OUT/$name" << 'EOF' +#!/bin/sh +dir=$(dirname "$0") +"$dir/${pkg}" "$@" +EOF + chmod +x "$OUT/$name" +done diff --git a/.clusterfuzzlite/project.yaml b/.clusterfuzzlite/project.yaml new file mode 100644 index 0000000..d1ad0ae --- /dev/null +++ b/.clusterfuzzlite/project.yaml @@ -0,0 +1 @@ +language: python diff --git a/.github/workflows/cflite_pr.yml b/.github/workflows/cflite_pr.yml new file mode 100644 index 0000000..077a98b --- /dev/null +++ b/.github/workflows/cflite_pr.yml @@ -0,0 +1,42 @@ +name: ClusterFuzzLite PR fuzzing + +on: + pull_request: + paths: + - '**' +permissions: + contents: read + actions: read + +jobs: + fuzz: + runs-on: ubuntu-latest + concurrency: + group: ${{ github.workflow }}-${{ matrix.sanitizer }}-${{ github.ref }} + cancel-in-progress: true + strategy: + fail-fast: false + matrix: + sanitizer: [ address, undefined ] + + steps: + - name: Check out code + uses: actions/checkout@v3 + + - name: Build Fuzzers (${{ matrix.sanitizer }}) + id: build + uses: google/clusterfuzzlite/actions/build_fuzzers@40f9a53e632516d2ec9f738eadd284635529fbad + with: + language: python + github-token: ${{ secrets.GITHUB_TOKEN }} + sanitizer: ${{ matrix.sanitizer }} + + - name: Run Fuzzers (${{ matrix.sanitizer }}) + id: run + uses: google/clusterfuzzlite/actions/run_fuzzers@40f9a53e632516d2ec9f738eadd284635529fbad + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + fuzz-seconds: 300 + mode: code-change + sanitizer: ${{ matrix.sanitizer }} + output-sarif: true diff --git a/tests/fuzzing/safe_decode_fuzzer.py b/tests/fuzzing/safe_decode_fuzzer.py new file mode 100644 index 0000000..1cfff19 --- /dev/null +++ b/tests/fuzzing/safe_decode_fuzzer.py @@ -0,0 +1,23 @@ +# SPDX-FileCopyrightText: Copyright 2025 Arm Limited and/or its affiliates +# SPDX-License-Identifier: Apache-2.0 + +import atheris +import sys +from metis.utils import safe_decode_unicode + + +def TestOneInput(data): + s = data.decode("utf-8", errors="ignore") + try: + _ = safe_decode_unicode(s) + except Exception: + pass + + +def main(): + atheris.Setup(sys.argv, TestOneInput) + atheris.Fuzz() + + +if __name__ == "__main__": + main()