Skip to content
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 a subcommand to build a clusterfuzz tarball #162

Merged
merged 5 commits into from
Sep 27, 2023

Conversation

Ekleog-NEAR
Copy link
Contributor

This makes it very to use bolero on clusterfuzz deployments, like private ones or oss-fuzz (though I have only tested with a private deployment, not having access to an oss-fuzz-enabled project).

This builds upon #161, so please ignore the first two commits for the review. Once #161 lands I’ll rebase on top of master, but clusterfuzz requires a working -jobs option to actually work.

Fixes #98

@Ekleog-NEAR
Copy link
Contributor Author

Ok, this is now rebased and ready for review! If you need any specific information regarding clusterfuzz please feel free to ask; the overall idea is to build a tarball that has all the test binaries so they’re not detected as fuzzers by clusterfuzz, and to add shell scripts detected as fuzzers by clusterfuzz that just call the test binaries with the proper cargo-bolero way of passing arguments :)

@Ekleog-NEAR
Copy link
Contributor Author

Ekleog-NEAR commented Sep 12, 2023

Oh, just to also say: clusterfuzz also theoretically supports afl, honggfuzz, syzcaller and other fuzzer types. I haven’t gotten to the point of implementing that yet, but I think the current PR would easily be extendable for it: we’d only have to add a --engine parameter like other commands.

Another potential future improvement would be to be able to filter the list of bolero tests, so that only some of them get introduced in the clusterfuzz tarball. TBH, I don’t think this would be necessary apart from very specific use cases (even within the already specific use case of clusterfuzz/oss-fuzz), so I don’t think it’s worth implementing it right now, especially when other fuzzer types aren’t supported yet :)

Comment on lines 23 to 24
std::fs::create_dir_all(OUTPUT_DIR).context("creating clusterfuzz build directory")?;
let output_path = Path::new(OUTPUT_DIR).join("clusterfuzz.tar");
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This technically means you have to run this command in the root of the workspace. Can we join the manifest dir to behave more like cargo?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, the only drawback is it requires a new dependency on cargo_metadata so as to not re-implement it all, but it’s only a dependency from cargo-bolero so it should be fine :)

Comment on lines 36 to 39
assert!(
t.is_harnessed,
"Non-harnessed tests are not supported for clusterfuzz yet"
);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what prevents us from supporting non-harnessed tests here. You just don't pass the libtest args, similar to what we did with libfuzzer.

Copy link
Contributor Author

@Ekleog-NEAR Ekleog-NEAR Sep 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBH it’s mostly that I don’t understand what exactly a non-harnessed test is or how it works exactly, so I didn’t want to fake support for it 😅

[edit: now-useless wall of code]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I just found my first example of non-harnessed tests while trying to write the integration test, and can confirm that this seems to work fine!

Comment on lines +138 to +184
(TESTFN.as_mut().expect("uninitialized test function"))(data_slice);
0
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this changed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and the below are due to the way test failures get recognized by clusterfuzz. Sorry I forgot to point towards the commit message, where I had explained it 😅
Here it is:

LLVMFuzzerTestOneInput is not supposed to ever return something other
than 0. Instead, the whole process should abort in case of a bug being
detected.

Hence, this replaces the previous returning of 1 (which triggered a
libfuzzer assertion downstream, that was detected by clusterfuzz as the
root cause of the error) by an abort (which lets clusterfuzz detect the
actual cause of the error in the panic message)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See also https://www.llvm.org/docs/LibFuzzer.html#fuzz-target ; where values other than 0 and -1 are "reserved for future use"

}

std::process::abort();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this changed?


/// Builds a tarball for uploading to clusterfuzz
#[derive(Debug, StructOpt)]
pub struct BuildClusterfuzz {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add an integration test that shows this all works how we would expect? I'm not familiar with clusterfuzz and don't want to have an accidental regression in behavior in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I’ve added a reasonable-ish integration test in the cargo_bolero.rs file.

Hopefully I have now handled all your review comments! Please let me know what you think about the new code, and the integration test that gives an example of how clusterfuzz runs the fuzzers :)

LLVMFuzzerTestOneInput is not supposed to ever return something other
than 0. Instead, the whole process should abort in case of a bug being
detected.

Hence, this replaces the previous returning of 1 (which triggered a
libfuzzer assertion downstream, that was detected by clusterfuzz as the
root cause of the error) by an abort (which should let clusterfuzz
detect the actual cause of the error in the panic message)
@Ekleog-NEAR Ekleog-NEAR force-pushed the build-clusterfuzz branch 2 times, most recently from 566e9cc to 35dd63b Compare September 26, 2023 23:27
@camshaft camshaft merged commit 6f68cd1 into camshaft:master Sep 27, 2023
9 checks passed
@Ekleog-NEAR
Copy link
Contributor Author

Thank you for the two reviews and merges! :D

@camshaft
Copy link
Owner

I'm planning on making one more PR and then I'll get a release out

@Ekleog-NEAR
Copy link
Contributor Author

Awesome, thank you! On my end I’m currently switching our infra to the current tip of master (near/nearcore#9603) ; will be able to confirm that everything works fine once it lands and a few days pass :)

(The not-yet-landed code is already in production at https://github.com/near/finite-wasm/blob/main/.github/workflows/fuzz.yml#L34; I’ll switch it to the release once it’s out)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Running cargo-bolero jobs on ClusterFuzz
3 participants