Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions .github/workflows/fuzz.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: "Fuzz"

# Coverage-guided fuzzing of the Jazzer targets in sdk/src/test/java/io/opentdf/platform/sdk/Fuzzing.java.
# Fuzzing takes the full maxDuration per target, so it runs after merges to main that touch the fuzzed code
# rather than on pull requests. The corpus Jazzer builds is cached between runs so that each run picks up
# where the last one stopped.

on:
push:
branches:
- main
paths:
- "sdk/src/**"
- "**/pom.xml"
- ".github/workflows/fuzz.yaml"
workflow_dispatch:
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Comment thread
dmihalcik-virtru marked this conversation as resolved.

# a burst of merges queues a single run of the latest commit instead of one run each
concurrency:
group: fuzz

permissions:
contents: read

jobs:
fuzz:
name: "Fuzz ${{ matrix.target }}"
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
target:
- fuzzZipRead
- fuzzTDF
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
Comment thread
dmihalcik-virtru marked this conversation as resolved.
with:
persist-credentials: false
- uses: bufbuild/buf-setup-action@a47c93e0b1648d5651a065437926377d060baa99 # v1.50.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Cache Maven packages
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Set up JDK
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
java-version: "17"
distribution: "temurin"
server-id: github
- name: Restore fuzzing corpus
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: sdk/.cifuzz-corpus
key: fuzz-corpus-${{ matrix.target }}-${{ github.run_id }}
restore-keys: fuzz-corpus-${{ matrix.target }}-
- name: Generate sources
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BUF_INPUT_HTTPS_USERNAME: opentdf-bot
BUF_INPUT_HTTPS_PASSWORD: ${{ secrets.PERSONAL_ACCESS_TOKEN_OPENTDF }}
run: mvn --batch-mode clean generate-sources -Denforcer.skip
- name: Fuzz
env:
JAZZER_FUZZ: "1"
run: |
# the default non-fips profile needs the sdk-fips-bc jar installed
mvn --batch-mode install -pl sdk-fips-bc -am \
-Dmaven.antrun.skip \
-Dmaven.test.skip \
-Denforcer.skip
mvn --batch-mode test -pl sdk \
-Dmaven.antrun.skip \
-Denforcer.skip \
-Dtest='Fuzzing#${{ matrix.target }}' \
-Dsurefire.failIfNoSpecifiedTests=false
- name: Save fuzzing corpus
if: always()
uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: sdk/.cifuzz-corpus
key: fuzz-corpus-${{ matrix.target }}-${{ github.run_id }}
- name: Upload findings
if: failure()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: fuzz-findings-${{ matrix.target }}
# Jazzer writes the input that triggered a finding next to the checked in inputs. Commit it there
# once fixed so that it replays as a regression test
path: |
sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/${{ matrix.target }}/crash-*
sdk/target/surefire-reports/
if-no-files-found: ignore
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ sdk/src/main/protogen
target/
.vscode/
.DS_Store
sdk/sample.tdf
sdk/sample.tdf
# Jazzer corpus generated by fuzzing runs
.cifuzz-corpus/
7 changes: 5 additions & 2 deletions sdk/src/test/java/io/opentdf/platform/sdk/Fuzzing.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,11 @@ public void fuzzZipRead(FuzzedDataProvider data) {
byte[] fuzzBytes = data.consumeRemainingAsBytes();
try {
ZipReaderTest.testReadingZipChannel(new SeekableInMemoryByteChannel(fuzzBytes), false);
} catch (InvalidZipException | IllegalArgumentException | JsonParseException | IOException e) {
// cases which are expected with invalid fuzzed inputs
} catch (InvalidZipException | JsonParseException | IOException e) {
// cases which are expected with invalid fuzzed inputs. JsonParseException comes from
// parsing the .json entries, not the zip. anything else the reader throws on bad
// input, such as an IllegalArgumentException from seeking to a corrupt offset, is a
// bug for the fuzzer to find
}
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading