Skip to content

Commit a2a557c

Browse files
Fuzzing: Integrate ClusterFuzzLite (#151)
1 parent 523d4ce commit a2a557c

File tree

11 files changed

+215
-15
lines changed

11 files changed

+215
-15
lines changed

.clusterfuzzlite/Dockerfile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
FROM gcr.io/oss-fuzz-base/base-builder-swift:v1
2+
RUN apt-get update && apt-get install -y make autoconf automake libtool
3+
ENV SWIFT_PREFIX=/opt/swift
4+
RUN mkdir -p "$SWIFT_PREFIX" && \
5+
curl -L https://download.swift.org/swift-6.0.1-release/ubuntu2004/swift-6.0.1-RELEASE/swift-6.0.1-RELEASE-ubuntu20.04.tar.gz | tar xz -C "$SWIFT_PREFIX" --strip-component 1
6+
ENV PATH="$SWIFT_PREFIX/usr/bin:$PATH"
7+
COPY . $SRC/wasmkit
8+
WORKDIR $SRC/wasmkit
9+
COPY .clusterfuzzlite/build.sh $SRC/

.clusterfuzzlite/build.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/bash -eu
2+
3+
cd FuzzTesting
4+
./fuzz.py --verbose build --sanitizer="$SANITIZER" FuzzTranslator
5+
6+
find .build/debug/ -maxdepth 1 -type f -name "Fuzz*" -executable -exec cp {} "$OUT/" \;
7+

.clusterfuzzlite/project.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
language: swift

.github/workflows/cflite_batch.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: ClusterFuzzLite batch fuzzing
2+
on:
3+
schedule:
4+
- cron: '0 0/6 * * *'
5+
permissions: read-all
6+
jobs:
7+
BatchFuzzing:
8+
runs-on: ubuntu-latest
9+
strategy:
10+
fail-fast: false
11+
matrix:
12+
sanitizer:
13+
- address
14+
steps:
15+
- name: Build Fuzzers (${{ matrix.sanitizer }})
16+
id: build
17+
uses: google/clusterfuzzlite/actions/build_fuzzers@v1
18+
with:
19+
language: swift
20+
sanitizer: ${{ matrix.sanitizer }}
21+
- name: Run Fuzzers (${{ matrix.sanitizer }})
22+
id: run
23+
uses: google/clusterfuzzlite/actions/run_fuzzers@v1
24+
with:
25+
github-token: ${{ secrets.GITHUB_TOKEN }}
26+
fuzz-seconds: 3600
27+
mode: 'batch'
28+
sanitizer: ${{ matrix.sanitizer }}
29+
output-sarif: true
30+
storage-repo: https://${{ secrets.SWIFTWASM_BOT_GITHUB_TOKEN }}@github.com/swiftwasm/wasmkit-fuzz-corpora.git
31+
storage-repo-branch: main
32+
storage-repo-branch-coverage: gh-pages

.github/workflows/cflite_build.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: ClusterFuzzLite continuous builds
2+
on:
3+
push:
4+
branches:
5+
- main
6+
permissions: read-all
7+
jobs:
8+
Build:
9+
runs-on: ubuntu-latest
10+
concurrency:
11+
group: ${{ github.workflow }}-${{ matrix.sanitizer }}-${{ github.ref }}
12+
cancel-in-progress: true
13+
strategy:
14+
fail-fast: false
15+
matrix:
16+
sanitizer:
17+
- address
18+
steps:
19+
- name: Build Fuzzers (${{ matrix.sanitizer }})
20+
id: build
21+
uses: google/clusterfuzzlite/actions/build_fuzzers@v1
22+
with:
23+
language: swift
24+
sanitizer: ${{ matrix.sanitizer }}
25+
upload-build: true

.github/workflows/cflite_cron.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: ClusterFuzzLite cron tasks
2+
on:
3+
schedule:
4+
- cron: '0 0 * * *'
5+
permissions: read-all
6+
jobs:
7+
Pruning:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- name: Build Fuzzers
11+
id: build
12+
uses: google/clusterfuzzlite/actions/build_fuzzers@v1
13+
with:
14+
language: swift
15+
- name: Run Fuzzers
16+
id: run
17+
uses: google/clusterfuzzlite/actions/run_fuzzers@v1
18+
with:
19+
github-token: ${{ secrets.GITHUB_TOKEN }}
20+
fuzz-seconds: 600
21+
mode: 'prune'
22+
output-sarif: true
23+
storage-repo: https://${{ secrets.SWIFTWASM_BOT_GITHUB_TOKEN }}@github.com/swiftwasm/wasmkit-fuzz-corpora.git
24+
storage-repo-branch: main
25+
storage-repo-branch-coverage: gh-pages
26+
Coverage:
27+
runs-on: ubuntu-latest
28+
steps:
29+
- name: Build Fuzzers
30+
id: build
31+
uses: google/clusterfuzzlite/actions/build_fuzzers@v1
32+
with:
33+
language: swift
34+
sanitizer: coverage
35+
- name: Run Fuzzers
36+
id: run
37+
uses: google/clusterfuzzlite/actions/run_fuzzers@v1
38+
with:
39+
github-token: ${{ secrets.GITHUB_TOKEN }}
40+
fuzz-seconds: 600
41+
mode: 'coverage'
42+
sanitizer: 'coverage'
43+
storage-repo: https://${{ secrets.SWIFTWASM_BOT_GITHUB_TOKEN }}@github.com/swiftwasm/wasmkit-fuzz-corpora.git
44+
storage-repo-branch: main
45+
storage-repo-branch-coverage: gh-pages

.github/workflows/cflite_pr.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: ClusterFuzzLite PR fuzzing
2+
on:
3+
pull_request:
4+
paths:
5+
- '**'
6+
permissions: read-all
7+
jobs:
8+
PR:
9+
name: PR Fuzzing (${{ matrix.sanitizer }} sanitizer)
10+
runs-on: ubuntu-latest
11+
concurrency:
12+
group: ${{ github.workflow }}-${{ matrix.sanitizer }}-${{ github.ref }}
13+
cancel-in-progress: true
14+
strategy:
15+
fail-fast: false
16+
matrix:
17+
sanitizer:
18+
- address
19+
steps:
20+
- name: Build Fuzzers (${{ matrix.sanitizer }})
21+
id: build
22+
uses: google/clusterfuzzlite/actions/build_fuzzers@v1
23+
with:
24+
language: swift
25+
github-token: ${{ secrets.GITHUB_TOKEN }}
26+
sanitizer: ${{ matrix.sanitizer }}
27+
storage-repo: https://${{ secrets.SWIFTWASM_BOT_GITHUB_TOKEN }}@github.com/swiftwasm/wasmkit-fuzz-corpora.git
28+
storage-repo-branch: main
29+
storage-repo-branch-coverage: gh-pages
30+
- name: Run Fuzzers (${{ matrix.sanitizer }})
31+
id: run
32+
uses: google/clusterfuzzlite/actions/run_fuzzers@v1
33+
with:
34+
github-token: ${{ secrets.GITHUB_TOKEN }}
35+
fuzz-seconds: 300
36+
mode: 'code-change'
37+
sanitizer: ${{ matrix.sanitizer }}
38+
output-sarif: true
39+
storage-repo: https://${{ secrets.SWIFTWASM_BOT_GITHUB_TOKEN }}@github.com/swiftwasm/wasmkit-fuzz-corpora.git
40+
storage-repo-branch: main
41+
storage-repo-branch-coverage: gh-pages

.github/workflows/format.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ on:
55
jobs:
66
format:
77
runs-on: ubuntu-latest
8+
concurrency:
9+
group: ${{ github.workflow }}-${{ github.ref }}
10+
cancel-in-progress: true
811
container:
912
image: swift:6.0.1-jammy
1013
steps:

.github/workflows/main.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ on:
55
push:
66
branches: [main]
77

8+
concurrency:
9+
group: ${{ github.workflow }}-${{ github.ref }}
10+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
11+
812
jobs:
913
build-macos:
1014
strategy:
@@ -16,12 +20,14 @@ jobs:
1620
development-toolchain-tag: swift-DEVELOPMENT-SNAPSHOT-2024-07-08-a
1721
wasi-swift-sdk-download: "https://github.com/swiftwasm/swift/releases/download/swift-wasm-DEVELOPMENT-SNAPSHOT-2024-07-09-a/swift-wasm-DEVELOPMENT-SNAPSHOT-2024-07-09-a-wasm32-unknown-wasi.artifactbundle.zip"
1822
wasi-swift-sdk-id: DEVELOPMENT-SNAPSHOT-2024-07-09-a-wasm32-unknown-wasi
23+
test-args: ""
1924
# Swift 5.9.0
2025
- os: macos-13
2126
xcode: Xcode_15.0.1
2227
development-toolchain-tag: swift-DEVELOPMENT-SNAPSHOT-2024-07-08-a
2328
wasi-swift-sdk-download: "https://github.com/swiftwasm/swift/releases/download/swift-wasm-DEVELOPMENT-SNAPSHOT-2024-07-09-a/swift-wasm-DEVELOPMENT-SNAPSHOT-2024-07-09-a-wasm32-unknown-wasi.artifactbundle.zip"
2429
wasi-swift-sdk-id: DEVELOPMENT-SNAPSHOT-2024-07-09-a-wasm32-unknown-wasi
30+
test-args: "--sanitize address"
2531

2632
runs-on: ${{ matrix.os }}
2733
name: "build-macos (${{ matrix.xcode }})"
@@ -52,7 +58,7 @@ jobs:
5258
}
5359
EOS
5460
- run: ./Vendor/checkout-dependency
55-
- run: swift test --sanitize address
61+
- run: swift test ${{ matrix.test-args }}
5662

5763
build-xcode:
5864
runs-on: macos-15

FuzzTesting/Package.swift

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,29 @@
1-
// swift-tools-version: 5.10
1+
// swift-tools-version: 5.8
22

33
import PackageDescription
44

55
let package = Package(
66
name: "FuzzTesting",
77
products: [
8+
// Discussion: Why we build libraries instead of executables linking libFuzzer?
9+
//
10+
// First, libclang_rt.fuzzer.a defines the main function for the fuzzing process
11+
// and object files given by the user are expected not to have a "main" function
12+
// to avoid conflicts.
13+
// Fortunately, SwiftPM asks the compiler frontend to define the main entrypoint as
14+
// `<module_name>_main` for testing executable targets (`-entry-point-function-name`)
15+
// so object files of `executableTarget` targets are capable of being linked with
16+
// libclang_rt.fuzzer.a.
17+
// However, at link-time, SwiftPM asks the linker to rename the `<module_name>_main`
18+
// symbol back to `main` for the final executable (`--defsym main=<module_name>_main`)
19+
// and gold linker respects the renamed "main" symbol rather than the one defined in
20+
// libclang_rt.fuzzer.a, so the final executable does not start the fuzzing process.
21+
//
22+
// Instead of relying on the SwiftPM's linking process, we build libraries defining
23+
// fuzzing target functions and manually link them with fuzzing runtime libraries.
824
.library(name: "FuzzTranslator", type: .static, targets: ["FuzzTranslator"]),
925
.library(name: "FuzzExecute", type: .static, targets: ["FuzzExecute"]),
26+
// FuzzDifferential is not a libFuzzer-based target, so we build it as an executable.
1027
.executable(name: "FuzzDifferential", targets: ["FuzzDifferential"]),
1128
],
1229
dependencies: [
@@ -27,10 +44,3 @@ let package = Package(
2744
.target(name: "WasmCAPI"),
2845
]
2946
)
30-
31-
let libFuzzerTargets = ["FuzzTranslator", "FuzzExecute"]
32-
33-
for target in package.targets {
34-
guard libFuzzerTargets.contains(target.name) else { continue }
35-
target.swiftSettings = [.unsafeFlags(["-Xfrontend", "-sanitize=fuzzer,address"])]
36-
}

0 commit comments

Comments
 (0)