Skip to content

Commit

Permalink
Merge pull request #395 from OWASP/fix-clusterfuzz
Browse files Browse the repository at this point in the history
Adding hypothesis test example and start on the first cornucopia fuzzer
  • Loading branch information
rewtd authored Apr 17, 2024
2 parents 33bd1f1 + 997da26 commit c3920ee
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 20 deletions.
9 changes: 7 additions & 2 deletions .clusterfuzzlite/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
FROM gcr.io/oss-fuzz-base/base-builder-python:v1@sha256:3434621b4da345fffd8d4b1342f3b6d8ad1b5510cdd8830b4bc4419d20b5855f
RUN apt-get update && apt-get install -y make autoconf automake libtool
RUN apt-get update && apt-get install -y make autoconf automake libtool curl gcc libc-dev software-properties-common
RUN add-apt-repository ppa:deadsnakes/ppa -y
RUN apt upgrade -y && apt-get install -y python3.10 python3.10-dev python3.10-distutils
RUN apt-get install -y python3-pip
RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python3.10
RUN python3.10 -m pip install --upgrade setuptools setuptools_scm PyInstaller==6.6.0 # meson ninja numpy pybind11 cython pythran
COPY . $SRC/cornucopia
WORKDIR cornucopia
WORKDIR $SRC/cornucopia
COPY .clusterfuzzlite/build.sh $SRC/
28 changes: 18 additions & 10 deletions .clusterfuzzlite/build.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
#!/bin/bash -eu

# build project
# e.g.
# ./autogen.sh
# ./configure
# make -j$(nproc) all

# build fuzzers
# e.g.
# $CXX $CXXFLAGS -std=c++11 -Iinclude \
# /path/to/name_of_fuzzer.cc -o $OUT/name_of_fuzzer \
# $LIB_FUZZING_ENGINE /path/to/library.a
python3.10 -m pip install -r requirements.txt --require-hashes
python3.10 -m pip install -r install_cornucopia_deps.txt

# Build fuzzers into $OUT. These could be detected in other ways.
for fuzzer in $(find "$SRC/cornucopia/tests/scripts" -name '*_fuzzer.py'); do
fuzzer_basename=$(basename -s .py $fuzzer)
fuzzer_package=${fuzzer_basename}.pkg

python3.10 -m PyInstaller --distpath $OUT --onefile --exclude IPython --paths $SRC/cornucopia:$SRC/cornucopia/scripts --hidden-import scripts --collect-submodules scripts --name $fuzzer_package $fuzzer

echo "#!/bin/sh
# LLVMFuzzerTestOneInput for fuzzer detection.
echo "fuzzing now, this is what is here"
this_dir=\$(dirname \"\$0\")
ASAN_OPTIONS=\$ASAN_OPTIONS:symbolize=1:external_symbolizer_path=\$this_dir/llvm-symbolizer:detect_leaks=0 \
\$this_dir/$fuzzer_package \$@" > $OUT/$fuzzer_basename
chmod +x "$OUT/$fuzzer_basename"
done
15 changes: 7 additions & 8 deletions .github/workflows/cflite_pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ on:
pull_request:
paths:
- 'scripts/convert**'
- 'test/scripts/convert**'
- '.clusterfuzzlite/Dockerfile'
- '.clusterfuzzlite/build.sh'
- 'tests/scripts/convert**'
- '.github/workflows/cflite_pr.yml'
- 'tests/scripts/*_fuzzer.py'
- '.clusterfuzzlite/**'
permissions: read-all
jobs:
hardening:
uses: ./.github/workflows/hardening.yaml
PR:
runs-on: ubuntu-latest
needs: hardening
concurrency:
group: ${{ github.workflow }}-${{ matrix.sanitizer }}-${{ github.ref }}
cancel-in-progress: true
Expand All @@ -20,11 +24,6 @@ jobs:
- address
- undefined
steps:
- name: Harden Runner
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
with:
egress-policy: audit

- name: Build Fuzzers (${{ matrix.sanitizer }})
id: build
uses: google/clusterfuzzlite/actions/build_fuzzers@884713a6c30a92e5e8544c39945cd7cb630abcd1 # v1
Expand Down
Binary file added .hypothesis/unicode_data/13.0.0/charmap.json.gz
Binary file not shown.
Binary file added .hypothesis/unicode_data/13.0.0/codec-utf-8.json.gz
Binary file not shown.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,23 @@ check that your code have sufficient test coverage
make coverage-check
```

### Developing fuzzers

We are using ClusterFuzzlite as a continuous fuzzing solution in order to run tests locally you need oss-fuzz.
For more information on how to write tests see: https://google.github.io/clusterfuzzlite/build-integration/python-lang/

How to test locally:

```bash
export PATH_TO_PROJECT=$(pwd)
cd ../
git clone https://github.com/google/oss-fuzz
cd ../oss-fuzz
python infra/helper.py build_image --external $PATH_TO_PROJECT
python infra/helper.py build_fuzzers --external $PATH_TO_PROJECT --sanitizer address
python infra/helper.py check_build --external $PATH_TO_PROJECT --sanitizer address
```

### Golden files

All python unit tests with fixtures in `testdata` folder support updating _golden_ files from real output of tests
Expand Down
40 changes: 40 additions & 0 deletions install_cornucopia_deps.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
black == 24.3.0 --hash=sha256:e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7
coverage == 7.4.4 --hash=sha256:690db6517f09336559dc0b5f55342df62370a48f5469fabf502db2c6d1cffcd2
flake8 == 7.0.0 --hash=sha256:a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3
httpretty == 1.1.4 --hash=sha256:20de0e5dd5a18292d36d928cc3d6e52f8b2ac73daec40d41eb62dee154933b68
mypy == 1.9.0 --hash=sha256:49c87c15aed320de9b438ae7b00c1ac91cd393c1b854c2ce538e2a72d55df150
pytest == 8.1.1 --hash=sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7
pytest-cov == 5.0.0 --hash=sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652
freezegun == 1.4.0 --hash=sha256:55e0fc3c84ebf0a96a5aa23ff8b53d70246479e9a68863f1fcac5a3e52f19dd6
atheris == 2.3.0 --hash=sha256:b91cb296d60915c3efa4f6db48f09c4678b574cddb7ca98035f1cb9d9fb96f64
ujson == 5.8 --hash=sha256:40931d7c08c4ce99adc4b409ddb1bbb01635a950e81239c2382cfe24251b127a # Remove after getting the tests to work
idna == 3.6 --hash=sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f
pypng == 0.20220715.0 --hash=sha256:4a43e969b8f5aaafb2a415536c1a8ec7e341cd6a3f957fd5b5f32a4cfeed902c
qrcode == 7.4.2 --hash=sha256:581dca7a029bcb2deef5d01068e39093e80ef00b4a61098a2182eac59d01643a
requests == 2.31.0 --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f
types-requests == 2.31.0.20240402 --hash=sha256:bd7eb7102168d4b5b489f15cdd9842b63ab7fe56aa82a0589fa595b94195acf4
typing_extensions == 4.8.0 --hash=sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0
urllib3 == 2.2.1 --hash=sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d
charset-normalizer == 3.3.2 --hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5
python-docx == 1.1.0 --hash=sha256:bac9773278098a1ddc43a52d84e22f5909c4a3080a624530b3ecb3771b07c6cd
PyYAML == 6.0.1 --hash=sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515
pyqrcode == 1.2.1 --hash=sha256:1b2812775fa6ff5c527977c4cd2ccb07051ca7d0bc0aecf937a43864abe5eff6
types-PyYAML == 6.0.12.12 --hash=sha256:c05bc6c158facb0676674b7f11fe3960db4f389718e19e62bd2b84d6205cfd24
lxml == 5.2.1 --hash=sha256:a2b44bec7adf3e9305ce6cbfa47a4395667e744097faed97abb4728748ba7d47 # Maybe problematic
docx2pdf == 0.1.8 --hash=sha256:6d2c20f9ad36eec75f4da017dc7a97622946954a6124ca0b11772875fa86fbed
pyinstaller == 5.13.2 --hash=sha256:c63ef6133eefe36c4b2f4daf4cfea3d6412ece2ca218f77aaf967e52a95ac9b8
click == 8.1.7 --hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28
mypy-extensions == 1.0.0 --hash=sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d
pathspec == 0.12.1 --hash=sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08
tomli == 2.0.1 --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc
mccabe == 0.7.0 --hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e
pycodestyle == 2.11.1 --hash=sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67
pyflakes == 3.2.0 --hash=sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a
iniconfig == 2.0.0 --hash=sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374
pluggy == 1.4.0 --hash=sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981
exceptiongroup == 1.2.0 --hash=sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14
python-dateutil == 2.9.0 --hash=sha256:cbf2f1da5e6083ac2fbfd4da39a25f34312230110440f424a14c7558bb85d82e
tqdm == 4.66.2 --hash=sha256:1ee4f8a893eb9bef51c6e35730cebf234d5d0b6bd112b0271e10ed7c24a02bd9
hypothesis == 6.99.13 --hash=sha256:b538df1d22365df84f94c38fb2d9c41a222373594c2a910cc8f4ddc68240a62f
attrs == 23.2.0 --hash=sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1
sortedcontainers == 2.4.0 --hash=sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0
29 changes: 29 additions & 0 deletions tests/scripts/get_suit_tags_and_key_fuzzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import unittest
from typing import List
import sys
import atheris

import convert as c

c.convert_vars = c.ConvertVars()


def TestOneInput(data):
test = unittest.TestCase()
fdp = atheris.FuzzedDataProvider(data)
input_key = fdp.ConsumeUnicodeNoSurrogates(1024)
want_tags: List[str] = []
want_key: str = ""
got_tags, got_key = c.get_suit_tags_and_key(input_key)
assert got_key == want_key
test.assertEqual(want_tags, got_tags)


def main():
atheris.instrument_all()
atheris.Setup(sys.argv, TestOneInput)
atheris.Fuzz()


if __name__ == "__main__":
main()

0 comments on commit c3920ee

Please sign in to comment.