-
Notifications
You must be signed in to change notification settings - Fork 93
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
Add advanced fuzzer #724
Add advanced fuzzer #724
Conversation
@@ -1007,6 +1007,7 @@ macro_rules! impl_instructions { | |||
/// Solely the opcode portion of an instruction represented as a single byte. | |||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] | |||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] | |||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is required for the previous fuzzing harness, which I fixed.
@@ -55,6 +55,8 @@ impl TryFrom<secp256k1::ecdsa::RecoveryId> for RecoveryId { | |||
/// Panics if the highest bit of byte at index 32 is set, as this indicates non-normalized | |||
/// signature. Panics if the recovery id is in reduced-x form. | |||
pub fn encode_signature(mut signature: [u8; 64], recovery_id: RecoveryId) -> [u8; 64] { | |||
// This assertion is hit during fuzzing. Verify it is safe to disable. | |||
#[cfg(not(any(fuzzing, feature = "test-helpers")))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth investigating. Is this assertion expected to be violated during fuzzing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Dentosal Why do we have an assertion here? It looks like the user can use an invalid signature, causing the crash. Maybe we need to return an error
@@ -112,6 +112,8 @@ impl Input { | |||
recover_address()? | |||
}; | |||
|
|||
// This error is reached during fuzzing often, verify it is safe to disable it | |||
#[cfg(not(any(fuzzing, feature = "test-helpers")))] | |||
if owner != &recovered_address { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth investigating. Is this assertion expected to be violated during fuzzing?
let max_program_length = 2usize.pow(18) | ||
- test_context.get_tx_params().tx_offset() | ||
- <fuel_vm::prelude::Script as Script>::script_offset_static() | ||
- 256; // TODO reevalute this one |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure where this magic value comes from, but I guess it is oke to have that.
@xgreenx Let me know how you want the corpus to be delivered :) I suggest an external repository that can be public or private. Private might be better to start with. I wanted to experiment with integrating a CI fuzzing, but that can follow up as separate PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just an overall question: do you have any ideas on how it can be integrated into our CI on a daily basis?
@@ -55,6 +55,8 @@ impl TryFrom<secp256k1::ecdsa::RecoveryId> for RecoveryId { | |||
/// Panics if the highest bit of byte at index 32 is set, as this indicates non-normalized | |||
/// signature. Panics if the recovery id is in reduced-x form. | |||
pub fn encode_signature(mut signature: [u8; 64], recovery_id: RecoveryId) -> [u8; 64] { | |||
// This assertion is hit during fuzzing. Verify it is safe to disable. | |||
#[cfg(not(any(fuzzing, feature = "test-helpers")))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Dentosal Why do we have an assertion here? It looks like the user can use an invalid signature, causing the crash. Maybe we need to return an error
@@ -112,6 +112,8 @@ impl Input { | |||
recover_address()? | |||
}; | |||
|
|||
// This error is reached during fuzzing often, verify it is safe to disable it | |||
#[cfg(not(any(fuzzing, feature = "test-helpers")))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious what problem you had here and how to reproduce it? Maybe we will have some ideas on how to address that in a better way
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have one at hand anymore, but removing the line and running the fuzzer should uncover it quickly. We can simply remove that for now and re-add it later on when you have CI fuzzing.
My idea was to experiment with https://google.github.io/clusterfuzzlite/ to add CI fuzzing in a future PR. |
// This error is reached during fuzzing often, verify it is safe to disable it | ||
#[cfg(not(any(fuzzing, feature = "test-helpers")))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// This error is reached during fuzzing often, verify it is safe to disable it | |
#[cfg(not(any(fuzzing, feature = "test-helpers")))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commit suggestion if you agree with that approach.
@xgreenx I think we want to add the no-changelog tag to this PR. Also the wasm checks seem to depend on the base branch being in the fuel-vm repository. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will merge it to our local branch to fix CI and add small modifications=)
* Add initial fuzz files * Fix original fuzz test * Add byte-based script functions back for fuzzing * Disable some errors for fuzzing * Fix new fuzz test due to changes in fuel-vm * Remove unused target * Add readme
* Add initial fuzz files * Fix original fuzz test * Add byte-based script functions back for fuzzing * Disable some errors for fuzzing * Fix new fuzz test due to changes in fuel-vm * Remove unused target * Add readme
* Add advanced fuzzer (#724) * Add initial fuzz files * Fix original fuzz test * Add byte-based script functions back for fuzzing * Disable some errors for fuzzing * Fix new fuzz test due to changes in fuel-vm * Remove unused target * Add readme * feat: Store example corpus in version control * chore: Instructions for how to generate a seed corpus * chore: Remove unused dependencies in binaries * fix: Cargo fmt * fix: Clippy * fix: Pass `fuzzing` as rustc flag when compiling fuzz binaries * feat: Remove broken `grammar_aware` fuzz target in favor of `grammar_aware_advanced` * feat: Default to LibAFL fuzzer * docs: Improve code coverage instructions * feat: Use feature flags to toggle between libFuzzer and LibAFL * docs: Further improvements to code coverage instructions * docs: Clarify what the execute binary does * fix: Minor cleanup * chore: Remove `arbitrary` dependency * feat: Link investigation ticket to ignored assertions * fix: Resurrect proptest arbitrary usage in `fuel-merkle` crate * fix: Remove gas statistics output * fix: typo in fuel-vm/fuzz/README.md Co-authored-by: AurelienFT <[email protected]> * chore: Remove example corpus and update README.md * fix: Minor enhancements from PR review * fix: Remove redundant magic 256 term * fix: Cargo fmt * chore: Bump secp256k1 version and re-enable disabled code paths for fuzzing * chore: Add changelog entry * fix: Clippy fix * fix: Format * Update fuel-crypto/src/secp256/signature_format.rs * chore: Add supported rust version to fuzzer readme * refactor: use `expect` instead of `unwrap` in a lot of places * refactor: Apply review suggestions * fix: More unwrap -> expect --------- Co-authored-by: Max Ammann <[email protected]> Co-authored-by: Mårten Blankfors <[email protected]> Co-authored-by: Mårten Blankfors <[email protected]> Co-authored-by: AurelienFT <[email protected]>
Adds a fuzzer which:
Manual
Generate Seeds
It is necessary to first convert Sway programs into a suitable format for use as seed input to the fuzzer. This can be done with the following command:
Running the Fuzzer
The Rust nightly version is required for executing cargo-fuzz. We also disable AddressSanitizer for a significant speed improvement, as we do not expect memory issues in a Rust program that does not use a significant amount of unsafe code, which our cargo-geiger analysis showed. It makes sense to leave AddressSanitizer turned on if the Fuel project uses more unsafe Rust in the future (either directly or through dependencies). The remaining flags are either required for LibAFL or are useful to make it use seven cores.
If you use libfuzzer (default) then the following command is enough:
Execute a Test Case
Test cases can be executed using the following command. This is useful for triaging issues.
Collect Statistics
We created a tool that writes gas statistics to a file called gas_statistics.csv. This can be used to analyze the execution time versus gas usage on a test corpus.
Generate Coverage
Regardless of how inputs are generated, it is important to measure a fuzzing campaign’s coverage after its run. To perform this measure, we used the support provided by cargo-fuzz and rustc. First, install cargo-binutils. After that, execute the following command:
Finally, generate an HTML file using LLVM:
The last argument to
cargo cov
defines the filter based on the host file paths.Checklist
Before requesting review
After merging, notify other teams
TODO