-
Notifications
You must be signed in to change notification settings - Fork 287
feat: add fuzzing support with Atheris and Docker configuration #2177
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
fa80dcb
feat: add fuzzing support with Atheris and Docker configuration
danielmarv 9a798e8
feat: add fuzzing support with Atheris and Docker configuration
danielmarv 7ce0849
feat: add fuzzing support with Atheris and Docker configuration
danielmarv a36dd29
refactor: address CodeRabbit review feedback
danielmarv 5f46918
fix: add timing tolerance to test_generate_with_jitter
danielmarv 677867c
feat: add fuzzing support with Atheris and Docker configuration
danielmarv c6cfcd6
Merge branch 'main' into fuzzle-sdk-br
danielmarv 4694c9a
refactor: clean up and formatting in fuzz targets
danielmarv a884693
Merge branch 'main' into fuzzle-sdk-br
danielmarv ec31a1d
refactor: update entity ID fuzz target and improve exception handling…
danielmarv 53388d7
Merge branch 'main' into fuzzle-sdk-br
danielmarv 06ce436
Merge branch 'main' into fuzzle-sdk-br
danielmarv 75ec43f
Merge branch 'main' into fuzzle-sdk-br
danielmarv 302be55
Merge branch 'main' into fuzzle-sdk-br
danielmarv 96dea7d
Merge branch 'main' into fuzzle-sdk-br
danielmarv 534b5de
Merge branch 'main' into fuzzle-sdk-br
danielmarv dd562fe
Merge branch 'main' into fuzzle-sdk-br
danielmarv bd99418
Merge branch 'main' into fuzzle-sdk-br
danielmarv 5c5a2d3
fix: specify exception types for validation errors in TestOneInput
danielmarv 319b9ea
Merge branch 'fuzzle-sdk-br' of https://github.com/danielmarv/hiero-s…
danielmarv ad9b14f
fix: specify exception types for validation errors in TestOneInput
danielmarv 9ad6e29
fix: specify exception types for validation errors in TestOneInput
danielmarv d20e0e2
Merge branch 'main' into fuzzle-sdk-br
danielmarv File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| FROM gcr.io/oss-fuzz-base/base-builder-python | ||
|
|
||
| RUN apt-get update && apt-get install -y --no-install-recommends \ | ||
| protobuf-compiler \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| COPY . $SRC/hiero-sdk-python | ||
| WORKDIR $SRC/hiero-sdk-python | ||
| COPY .clusterfuzzlite/build.sh $SRC/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| #!/bin/bash -eu | ||
|
|
||
| pip3 install grpcio-tools | ||
|
danielmarv marked this conversation as resolved.
|
||
|
|
||
| python3 generate_proto.py | ||
|
|
||
| pip3 install . | ||
|
|
||
| pip3 install atheris pyinstaller | ||
|
|
||
| find "$SRC/hiero-sdk-python/.clusterfuzzlite" -name '*_fuzzer.py' -print0 | while IFS= read -r -d '' fuzzer; do | ||
| fuzzer_basename=$(basename -s .py "$fuzzer") | ||
| fuzzer_package="${fuzzer_basename}.pkg" | ||
|
|
||
| # Bundle the fuzzer and all its dependencies into a single portable package. | ||
| pyinstaller --distpath "$OUT" --onefile --name "$fuzzer_package" "$fuzzer" | ||
|
|
||
| # Write a thin shell wrapper that ClusterFuzzLite uses to invoke the fuzzer. | ||
| # The wrapper preloads the sanitizer library and sets ASAN_OPTIONS. | ||
| # LD_PRELOAD is required here because the SDK uses C extensions (grpcio, | ||
| # cryptography, protobuf) that must be covered by the sanitizer. | ||
| cat > "$OUT/$fuzzer_basename" << EOF | ||
| #!/bin/sh | ||
| # LLVMFuzzerTestOneInput for fuzzer detection. | ||
| this_dir=\$(dirname "\$0") | ||
| LD_PRELOAD=\$this_dir/sanitizer_with_fuzzer.so \\ | ||
| PYCRYPTODOME_DISABLE_DEEPBIND=1 \\ | ||
| ASAN_OPTIONS=\$ASAN_OPTIONS:symbolize=1:external_symbolizer_path=\$this_dir/llvm-symbolizer:detect_leaks=0 \\ | ||
| "\$this_dir/$fuzzer_package" "\$@" | ||
| EOF | ||
| chmod +x "$OUT/$fuzzer_basename" | ||
| done | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| """Atheris fuzz target: ContractFunctionParameters ABI encoding.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import sys | ||
|
|
||
| import atheris | ||
|
|
||
|
|
||
| with atheris.instrument_imports(): | ||
| from eth_abi.exceptions import EncodingTypeError, ValueOutOfBounds | ||
|
|
||
| from hiero_sdk_python import ContractFunctionParameters | ||
|
|
||
|
|
||
| def TestOneInput(data: bytes) -> None: | ||
| """Feed arbitrary bytes into ContractFunctionParameters encoding paths.""" | ||
| fdp = atheris.FuzzedDataProvider(data) | ||
| choice = fdp.ConsumeIntInRange(0, 9) | ||
| params = ContractFunctionParameters() | ||
| if choice == 0: | ||
| params.add_bool(fdp.ConsumeBool()) | ||
| elif choice == 1: | ||
| # add_address expects a 20-byte hex string or bytes | ||
| params.add_address(fdp.ConsumeBytes(20).hex()) | ||
| elif choice == 2: | ||
| params.add_string(fdp.ConsumeUnicodeNoSurrogates(256)) | ||
| elif choice == 3: | ||
| params.add_bytes(fdp.ConsumeBytes(256)) | ||
| elif choice == 4: | ||
|
exploreriii marked this conversation as resolved.
|
||
| params.add_bytes32(fdp.ConsumeBytes(32)) | ||
| elif choice == 5: | ||
| count = fdp.ConsumeIntInRange(0, 8) | ||
| params.add_bool_array([fdp.ConsumeBool() for _ in range(count)]) | ||
| elif choice == 6: | ||
| count = fdp.ConsumeIntInRange(0, 8) | ||
| params.add_string_array([fdp.ConsumeUnicodeNoSurrogates(64) for _ in range(count)]) | ||
| elif choice == 7: | ||
| count = fdp.ConsumeIntInRange(0, 8) | ||
| params.add_bytes_array([fdp.ConsumeBytes(32) for _ in range(count)]) | ||
| elif choice == 8: | ||
| count = fdp.ConsumeIntInRange(0, 8) | ||
| params.add_address_array([fdp.ConsumeBytes(20).hex() for _ in range(count)]) | ||
| else: | ||
| count = fdp.ConsumeIntInRange(0, 8) | ||
| params.add_bytes32_array([fdp.ConsumeBytes(32) for _ in range(count)]) | ||
|
exploreriii marked this conversation as resolved.
|
||
| try: | ||
| params.to_bytes() | ||
| except (TypeError, ValueError, EncodingTypeError, ValueOutOfBounds): | ||
| # Malformed fuzz input can trigger expected validation/ABI encoding failures. | ||
| pass | ||
|
|
||
|
|
||
| atheris.Setup(sys.argv, TestOneInput) | ||
| atheris.Fuzz() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| """Atheris fuzz target: entity ID string parsing.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import sys | ||
|
|
||
| import atheris | ||
|
|
||
|
|
||
| with atheris.instrument_imports(): | ||
| from hiero_sdk_python import AccountId, ContractId, FileId, TokenId, TopicId | ||
|
|
||
| _CLASSES = (AccountId, TokenId, ContractId, FileId, TopicId) | ||
|
|
||
|
|
||
| def _try_parse_entity_id(entity_id_class, text: str) -> None: | ||
| try: | ||
| entity_id_class.from_string(text) | ||
| except (TypeError, ValueError, IndexError, OverflowError): | ||
| # Expected errors from malformed string input (parsing, indexing, conversions) | ||
| pass | ||
|
|
||
|
|
||
| def TestOneInput(data: bytes) -> None: | ||
| """Feed arbitrary strings into entity ID parsers.""" | ||
| fdp = atheris.FuzzedDataProvider(data) | ||
| text = fdp.ConsumeUnicodeNoSurrogates(256) | ||
|
|
||
| for cls in _CLASSES: | ||
| _try_parse_entity_id(cls, text) | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
|
|
||
| atheris.Setup(sys.argv, TestOneInput) | ||
| atheris.Fuzz() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| """Atheris fuzz target: PrivateKey and PublicKey parsing.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import sys | ||
| import warnings | ||
|
|
||
| import atheris | ||
|
|
||
|
|
||
| with atheris.instrument_imports(): | ||
| from hiero_sdk_python import PrivateKey, PublicKey | ||
|
|
||
|
|
||
| def _quiet(fn, *args): | ||
| """Call *fn* with *args*, suppressing UserWarning.""" | ||
| with warnings.catch_warnings(): | ||
| warnings.simplefilter("ignore", UserWarning) | ||
| return fn(*args) | ||
|
|
||
|
|
||
| def TestOneInput(data: bytes) -> None: | ||
| """Feed arbitrary bytes/strings into key parsers.""" | ||
| fdp = atheris.FuzzedDataProvider(data) | ||
| choice = fdp.ConsumeIntInRange(0, 3) | ||
|
|
||
| try: | ||
| if choice == 0: | ||
| text = fdp.ConsumeUnicodeNoSurrogates(256) | ||
| _quiet(PrivateKey.from_string, text) | ||
| elif choice == 1: | ||
| raw = fdp.ConsumeBytes(128) | ||
| _quiet(PrivateKey.from_bytes, raw) | ||
| elif choice == 2: | ||
| text = fdp.ConsumeUnicodeNoSurrogates(256) | ||
| _quiet(PublicKey.from_string, text) | ||
| else: | ||
| raw = fdp.ConsumeBytes(128) | ||
| _quiet(PublicKey.from_bytes, raw) | ||
| except ValueError: | ||
| pass | ||
|
|
||
|
|
||
| atheris.Setup(sys.argv, TestOneInput) | ||
| atheris.Fuzz() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| language: python |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| """Atheris fuzz target: Transaction.from_bytes deserialization.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import sys | ||
|
|
||
| import atheris | ||
|
|
||
|
|
||
| with atheris.instrument_imports(): | ||
| from hiero_sdk_python import Transaction | ||
|
|
||
|
|
||
| def TestOneInput(data: bytes) -> None: | ||
| """Feed arbitrary bytes into Transaction.from_bytes and re-serialise.""" | ||
| try: | ||
| tx = Transaction.from_bytes(data) | ||
| tx.to_bytes() | ||
| except Exception: | ||
| # Protobuf deserialization and transaction parsing can raise many | ||
| # exception types (DecodeError, ValueError, TypeError, KeyError, etc.); | ||
| # only unhandled exceptions that escape are reported as fuzzer crashes. | ||
| pass | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
|
|
||
| atheris.Setup(sys.argv, TestOneInput) | ||
| atheris.Fuzz() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| --- | ||
| exclude_paths: | ||
| - "tck/**" | ||
| - ".clusterfuzzlite/**" | ||
|
|
||
| engines: | ||
| bandit: | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| name: ClusterFuzzLite | ||
|
|
||
| on: | ||
| pull_request: | ||
| push: | ||
| branches: | ||
| - main | ||
|
coderabbitai[bot] marked this conversation as resolved.
danielmarv marked this conversation as resolved.
|
||
|
|
||
| permissions: read-all | ||
|
manishdait marked this conversation as resolved.
exploreriii marked this conversation as resolved.
|
||
|
|
||
| jobs: | ||
| # ── PR fuzzing ──────────────────────────────────────────────────────────── | ||
| # Runs on every pull request and reports any new crashes found in the | ||
| # changed code paths (code-change mode). | ||
| PR: | ||
| if: github.event_name == 'pull_request' | ||
| runs-on: hl-sdk-py-lin-md | ||
| concurrency: | ||
| group: ${{ github.workflow }}-pr-${{ matrix.sanitizer }}-${{ github.ref }} | ||
| cancel-in-progress: true | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| sanitizer: | ||
| - address | ||
| steps: | ||
| - name: Harden the runner (Audit all outbound calls) | ||
| uses: step-security/harden-runner@6c3c2f2c1c457b00c10c4848d6f5491db3b629df # v2.18.0 | ||
| with: | ||
| egress-policy: audit | ||
|
|
||
| - name: Build Fuzzers (${{ matrix.sanitizer }}) | ||
| id: build | ||
| uses: google/clusterfuzzlite/actions/build_fuzzers@884713a6c30a92e5e8544c39945cd7cb630abcd1 # v1 | ||
| with: | ||
| language: python | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| sanitizer: ${{ matrix.sanitizer }} | ||
|
|
||
| - name: Run Fuzzers (${{ matrix.sanitizer }}) | ||
| id: run | ||
| uses: google/clusterfuzzlite/actions/run_fuzzers@884713a6c30a92e5e8544c39945cd7cb630abcd1 # v1 | ||
| with: | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| fuzz-seconds: 600 | ||
| mode: code-change | ||
| sanitizer: ${{ matrix.sanitizer }} | ||
| output-sarif: true | ||
|
|
||
| # ── Continuous builds ───────────────────────────────────────────────────── | ||
| # Uploads a fresh fuzzer build artifact on every push to main so that PR | ||
| # fuzzing can determine whether a crash was newly introduced. | ||
| Build: | ||
| if: github.event_name == 'push' | ||
| runs-on: hl-sdk-py-lin-md | ||
| concurrency: | ||
| group: ${{ github.workflow }}-build-${{ matrix.sanitizer }}-${{ github.ref }} | ||
| cancel-in-progress: true | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| sanitizer: | ||
| - address | ||
| steps: | ||
| - name: Harden the runner (Audit all outbound calls) | ||
| uses: step-security/harden-runner@6c3c2f2c1c457b00c10c4848d6f5491db3b629df # v2.18.0 | ||
| with: | ||
| egress-policy: audit | ||
|
|
||
| - name: Build Fuzzers (${{ matrix.sanitizer }}) | ||
| id: build | ||
| uses: google/clusterfuzzlite/actions/build_fuzzers@884713a6c30a92e5e8544c39945cd7cb630abcd1 # v1 | ||
| with: | ||
| language: python | ||
| sanitizer: ${{ matrix.sanitizer }} | ||
| upload-build: true | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.