Skip to content

Commit 3d8b9aa

Browse files
gtreptaScott-Guest
andauthored
Use Honggfuzz for fuzzing targets (#1234)
* Convert fuzzing targets to honggfuzz * Update workflows for honggfuzz targets * Format * Clean up wasm_smith config generation * Allow ty_to_val to generate random values * Use fuel-metering and lazy compilation in execute harness * Disable tail calls for differential fuzzing * Remove dead code * Use sudo for apt-get * Fix clippy * Allow multiple memories where supported * Add comment for swarm module * Use CompilationMode::Eager for executor harness * Use existing Arbitrary instances for primitive types in ty_to_arbitrary_val --------- Co-authored-by: Scott Guest <[email protected]>
1 parent 2dbfdab commit 3d8b9aa

File tree

8 files changed

+225
-246
lines changed

8 files changed

+225
-246
lines changed

.github/workflows/rust.yml

Lines changed: 14 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -198,64 +198,12 @@ jobs:
198198
- name: Check uDeps
199199
run: cargo udeps --all-targets
200200

201-
fuzz-translate:
202-
name: Fuzz (Translation)
203-
runs-on: ubuntu-latest
204-
steps:
205-
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
206-
with:
207-
submodules: true
208-
- uses: dtolnay/rust-toolchain@master
209-
with:
210-
# Pin nightly so that it does not invalidate GitHub Actions cache too frequently.
211-
toolchain: nightly-2024-09-24
212-
- name: Set up Rust cache
213-
uses: Swatinem/rust-cache@v2
214-
with:
215-
cache-directories: |
216-
~/fuzz/corpus/translate/
217-
~/fuzz/corpus/translate_metered/
218-
- name: Install cargo-fuzz
219-
run: |
220-
# Note: We use `|| true` because cargo install returns an error
221-
# if cargo-udeps was already installed on the CI runner.
222-
cargo install cargo-fuzz || true
223-
- name: Build Fuzzing
224-
run: cargo fuzz build translate
225-
- name: Fuzz (Translation)
226-
run: cargo fuzz run translate -j 2 --verbose -- -max_total_time=60 # 1 minute of fuzzing
227-
- name: Fuzz (Translation) + fuel
228-
run: cargo fuzz run translate_metered -j 2 --verbose -- -max_total_time=60 # 1 minute of fuzzing
229-
230-
fuzz-execute:
231-
name: Fuzz (Execution)
232-
runs-on: ubuntu-latest
233-
steps:
234-
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
235-
with:
236-
submodules: true
237-
- uses: dtolnay/rust-toolchain@master
238-
with:
239-
# Pin nightly so that it does not invalidate GitHub Actions cache too frequently.
240-
toolchain: nightly-2024-09-24
241-
- name: Set up Rust cache
242-
uses: Swatinem/rust-cache@v2
243-
with:
244-
cache-directories: |
245-
~/fuzz/corpus/execute/
246-
- name: Install cargo-fuzz
247-
run: |
248-
# Note: We use `|| true` because cargo install returns an error
249-
# if cargo-udeps was already installed on the CI runner.
250-
cargo install cargo-fuzz || true
251-
- name: Build Fuzzing
252-
run: cargo fuzz build execute
253-
- name: Fuzz (Execution)
254-
run: cargo fuzz run execute -j 2 --verbose -- -max_total_time=120 # 2 minutes of fuzzing
255-
256-
fuzz-differential:
257-
name: Fuzz (Differential)
201+
fuzz:
202+
name: Fuzz
258203
runs-on: ubuntu-latest
204+
strategy:
205+
matrix:
206+
fuzz_target: ['translate', 'translate_metered', 'execute', 'differential']
259207
steps:
260208
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
261209
with:
@@ -268,16 +216,16 @@ jobs:
268216
uses: Swatinem/rust-cache@v2
269217
with:
270218
cache-directories: |
271-
~/fuzz/corpus/differential/
272-
- name: Install cargo-fuzz
219+
${{ github.workspace }}/hfuzz_target
220+
${{ github.workspace }}/hfuzz_workspace
221+
- name: Install cargo-honggfuzz and dependencies
273222
run: |
274-
# Note: We use `|| true` because cargo install returns an error
275-
# if cargo-udeps was already installed on the CI runner.
276-
cargo install cargo-fuzz || true
277-
- name: Build Fuzzing
278-
run: cargo fuzz build differential
279-
- name: Fuzz (Differential)
280-
run: cargo fuzz run differential -j 2 --verbose -- -max_total_time=120 # 2 minutes of fuzzing
223+
cargo install honggfuzz || true
224+
sudo apt-get update && sudo apt-get install --yes binutils-dev libunwind-dev
225+
- name: Run HFuzz
226+
env:
227+
HFUZZ_RUN_ARGS: "--run_time 120 --verbose --quiet" # 2 minutes of fuzzing
228+
run: cargo hfuzz run ${{ matrix.fuzz_target }}
281229

282230
miri:
283231
name: Miri

Cargo.lock

Lines changed: 37 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fuzz/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ edition.workspace = true
1111
cargo-fuzz = true
1212

1313
[dependencies]
14-
libfuzzer-sys = "0.4.7"
14+
honggfuzz = "0.5"
1515
wasmi-stack = { package = "wasmi", version = "0.31.2" }
1616
wasmtime = "21.0.1"
1717
wasmi = { workspace = true, features = ["std"] }

fuzz/fuzz_targets/differential.rs

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
#![no_main]
2-
31
mod utils;
42

5-
use libfuzzer_sys::fuzz_target;
3+
use arbitrary::Unstructured;
4+
use honggfuzz::fuzz;
65
use std::{collections::hash_map::RandomState, mem};
7-
use utils::{arbitrary_exec_module, ty_to_val};
6+
use utils::arbitrary_config;
87
use wasmi as wasmi_reg;
98
use wasmi_reg::core::{F32, F64};
109

@@ -68,7 +67,15 @@ impl WasmiRegister {
6867
}
6968

7069
fn type_to_value(ty: &wasmi_reg::core::ValType) -> wasmi_reg::Val {
71-
ty_to_val(ty)
70+
match ty {
71+
wasmi_reg::core::ValType::I32 => wasmi_reg::Val::I32(1),
72+
wasmi_reg::core::ValType::I64 => wasmi_reg::Val::I64(1),
73+
wasmi_reg::core::ValType::F32 => wasmi_reg::Val::F32(1.0.into()),
74+
wasmi_reg::core::ValType::F64 => wasmi_reg::Val::F64(1.0.into()),
75+
unsupported => panic!(
76+
"differential fuzzing does not support reference types, yet but found: {unsupported:?}"
77+
),
78+
}
7279
}
7380
}
7481

@@ -169,7 +176,7 @@ impl WasmiStack {
169176
ValueType::F32 => wasmi_stack::Value::F32(1.0.into()),
170177
ValueType::F64 => wasmi_stack::Value::F64(1.0.into()),
171178
unsupported => panic!(
172-
"execution fuzzing does not support reference types, yet but found: {unsupported:?}"
179+
"differential fuzzing does not support reference types, yet but found: {unsupported:?}"
173180
),
174181
}
175182
}
@@ -254,7 +261,7 @@ impl Wasmtime {
254261
wasmtime::ValType::F32 => wasmtime::Val::F32(1.0_f32.to_bits()),
255262
wasmtime::ValType::F64 => wasmtime::Val::F64(1.0_f64.to_bits()),
256263
unsupported => panic!(
257-
"execution fuzzing does not support reference types, yet but found: {unsupported:?}"
264+
"differential fuzzing does not support reference types, yet but found: {unsupported:?}"
258265
),
259266
}
260267
}
@@ -613,31 +620,44 @@ impl FuzzContext {
613620
}
614621
}
615622

616-
fuzz_target!(|data: &[u8]| {
617-
let Ok(mut smith_module) = arbitrary_exec_module(data) else {
618-
return;
619-
};
620-
// Note: We cannot use built-in fuel metering of the different engines since that
621-
// would introduce unwanted non-determinism with respect to fuzz testing.
622-
let Ok(_) = smith_module.ensure_termination(1_000 /* fuel */) else {
623-
return;
624-
};
625-
let wasm = smith_module.to_bytes();
626-
let Some(wasmi_register) = <WasmiRegister as DifferentialTarget>::setup(&wasm[..]) else {
627-
return;
628-
};
629-
let Some(wasmi_stack) = <WasmiStack as DifferentialTarget>::setup(&wasm[..]) else {
630-
panic!("wasmi (register) succeeded to create Context while wasmi (stack) failed");
631-
};
632-
let exports = wasmi_register.exports();
633-
let mut context = FuzzContext {
634-
wasm,
635-
wasmi_register,
636-
wasmi_stack,
637-
exports,
638-
};
639-
context.run();
640-
});
623+
fn main() {
624+
loop {
625+
fuzz!(|seed: &[u8]| {
626+
let mut unstructured = Unstructured::new(seed);
627+
let Ok(mut smith_module) =
628+
arbitrary_config(&mut unstructured).and_then(|mut config| {
629+
config.reference_types_enabled = false;
630+
config.tail_call_enabled = false;
631+
config.max_memories = 1;
632+
wasm_smith::Module::new(config, &mut unstructured)
633+
})
634+
else {
635+
return;
636+
};
637+
// Note: We cannot use built-in fuel metering of the different engines since that
638+
// would introduce unwanted non-determinism with respect to fuzz testing.
639+
let Ok(_) = smith_module.ensure_termination(1_000 /* fuel */) else {
640+
return;
641+
};
642+
let wasm = smith_module.to_bytes();
643+
let Some(wasmi_register) = <WasmiRegister as DifferentialTarget>::setup(&wasm[..])
644+
else {
645+
return;
646+
};
647+
let Some(wasmi_stack) = <WasmiStack as DifferentialTarget>::setup(&wasm[..]) else {
648+
panic!("wasmi (register) succeeded to create Context while wasmi (stack) failed");
649+
};
650+
let exports = wasmi_register.exports();
651+
let mut context = FuzzContext {
652+
wasm,
653+
wasmi_register,
654+
wasmi_stack,
655+
exports,
656+
};
657+
context.run();
658+
});
659+
}
660+
}
641661

642662
#[derive(Debug, Copy, Clone)]
643663
pub enum FuzzValue {

0 commit comments

Comments
 (0)