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

Introduce libafl-fuzz #2362

Merged
merged 48 commits into from
Jul 16, 2024

Conversation

R9295
Copy link
Collaborator

@R9295 R9295 commented Jul 3, 2024

There's a few TODOs before we can merge this but I'd like to get some input on the work already.

  • Clap does not allow environment only fields so I need to parse them manually. Currently the CLI is a bit buggy if you enter an invalid parameter
  • Setup CI
  • test-instr.c does not work with ForkserverExecutor since it has an old forkserver version? Find something else

cc @vanhauser-thc / @domenukk / @tokatoka

@R9295 R9295 marked this pull request as draft July 3, 2024 20:19
@tokatoka
Copy link
Member

tokatoka commented Jul 4, 2024

should we really put this into fuzzers/ ?
@domenukk

@tokatoka
Copy link
Member

tokatoka commented Jul 4, 2024

it could be in a separate repo

@domenukk
Copy link
Member

domenukk commented Jul 4, 2024

Yes otherwise it won't be maintained

@@ -0,0 +1,246 @@
#![feature(io_error_more)]
#![deny(clippy::pedantic)]
#![allow(clippy::unsafe_derive_deserialize)]
Copy link
Member

Choose a reason for hiding this comment

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

Copy&paste the massive amount of flags we use in libafl/lib.rs

Copy link
Collaborator Author

@R9295 R9295 Jul 6, 2024

Choose a reason for hiding this comment

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

Why? I would rather add it only if necessary and so far it hasn't been

Copy link
Member

Choose a reason for hiding this comment

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

You'll be forced to write cleaner code through annoying lints

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

clean code is good 🫡

fn main() {
env_logger::init();
let mut opt = Opt::parse();
executor::check_binary(&mut opt, SHMEM_ENV_VAR).expect("binary to be valid");
Copy link
Member

Choose a reason for hiding this comment

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

Pass in the binary into the function instead of the opt, and give some useful output on failure

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

opt is necessary since there are several checks that may be skipped if frida, qemu, non instrumented, skip bin check etc

Copy link
Member

Choose a reason for hiding this comment

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

Sad. Would still be good to pass in the needed flags only, but up to you. At least make the expect more meaningful?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The errors returned from check_binary will also be printed when the expect is triggered so should be fine.

/// The [`AflStatsStage`] is a Stage that calculates and writes
/// AFL++'s `fuzzer_stats` and `plot_data` information.
#[derive(Debug, Clone)]
pub struct AflStatsStage<E, EM, Z>
Copy link
Member

Choose a reason for hiding this comment

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

Think we could put that into the main lib

@domenukk
Copy link
Member

domenukk commented Jul 4, 2024

Looks good!

@R9295
Copy link
Collaborator Author

R9295 commented Jul 4, 2024

Post GSoC I think it makes sense to move it out of fuzzers. I would be happy to maintain it:)

@R9295 R9295 marked this pull request as ready for review July 15, 2024 15:32
@domenukk
Copy link
Member

CI isn't happy yet, a bunch of warnings and an error

}
impl Display for AFLFuzzerStats<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "start_time : {}", &self.start_time)?;
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if it's faster to format this and then do one big write, since every writeln may trigger a syscall

Copy link
Member

@domenukk domenukk Jul 15, 2024

Choose a reason for hiding this comment

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

As in, we coudl make this one a big

writeln!(f, "...
...
...
", ...)
  • uglier to read but potentially faster(?)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Will investigate

@@ -55,6 +58,12 @@ where
.map(|id| state.corpus().next(id))
.flatten()
.unwrap_or_else(|| state.corpus().first().unwrap());

self.runs_in_current_cycle += 1;
// TODO deal with corpus_counts decreasing due to removals
Copy link
Member

Choose a reason for hiding this comment

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

Can we already merge this anyway?

cc @tokatoka

Copy link
Collaborator Author

@R9295 R9295 Jul 15, 2024

Choose a reason for hiding this comment

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

IIRC yes since WeightedScheduler also handles it this way. Also TODO there

Copy link
Member

Choose a reason for hiding this comment

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

👍

load_callback,
}
}

#[allow(clippy::only_used_in_recursion)]
Copy link
Member

Choose a reason for hiding this comment

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

False positive? oO

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

error: parameter is only used in recursion
   --> libafl/src/stages/sync.rs:176:10
    |
176 |         &self,
    |          ^^^^
    |
note: parameter used here
   --> libafl/src/stages/sync.rs:203:40
    |
203 |                 let dir_left_to_sync = self.load_from_directory(&entry.path(), last)?;
    |                                        ^^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#only_used_in_recursion
note: the lint level is defined here
   --> libafl/src/lib.rs:18:9
    |
18  | #![deny(clippy::all)]
    |         ^^^^^^^^^^^
    = note: `#[deny(clippy::only_used_in_recursion)]` implied by `#[deny(clippy::all)]`

Copy link
Member

Choose a reason for hiding this comment

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

Ok technically load_from_directory could be a normal fn instead of being a method

Copy link
Member

Choose a reason for hiding this comment

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

So the clippy lint is correct

Copy link
Member

Choose a reason for hiding this comment

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

Take a look at #2402 what you think

@domenukk domenukk merged commit aa21815 into AFLplusplus:main Jul 16, 2024
101 checks passed
@domenukk
Copy link
Member

Congrats 🎉🎉🎉

.left_to_sync
.append(&mut new_files);
if let Some(last) = last {
if (last + self.interval) < current_time() {
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this the opposite?
You want to perform this stage once every while,
shouldn't this be current_time() < (last + self.interval)

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

But instead of the early return, I can wrap it in a different clause

Copy link
Member

Choose a reason for hiding this comment

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

what i mean is if you want early return if not enough time has passed
then it should be
(last + self.interval) > current_time()
right?

Copy link
Collaborator Author

@R9295 R9295 Jul 16, 2024

Choose a reason for hiding this comment

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

Ah yes, you're right. Whoops. I'll submit a fix

Copy link
Member

Choose a reason for hiding this comment

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

yeah it's confusing
maybe do something like

let cur = current_time();
if cur.checked_sub(last) < self.last {
 // early return
}

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.

3 participants