Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

What is the best way to resume CI fuzzing sessions, while continually updating seed corpus + merging AFL++ output queue. #2238

abhisen7 started this conversation in General
Discussion options

I am implementing CI-fuzzing to stress an SQL parser, for which the input corpus is a set of various queries supported by the database. Since the database is quickly growing, there will be new syntaxes and functions supported that will need to get added to the corpus from time to time.

In our current setup, we maintain this corpus under the same project repo where we keep the harness. Today, when a CI fuzzing campaign starts, it re-seeds the fuzzer with the entire input corpus. Before the job ends, crash data is uploaded to an internal S3 for analysis.

This ofc is not efficient in the long run, so I am thinking of saving the entire output (queue, fastresume.bin..) , and merging the previous queue with the incrementally updated input seed before the next run.

The problem is, I can't seem to understand how the fuzzing will be impacted, if I execute afl-fuzz -i merged_seed_with_previous_queue -o folder_containing_fastresume.bin /path/to/target. OTOH, AFL++ allows fuzz resumption with the i - flag, but then I miss out on seeding it with the new inputs.

Would appreciate some leads here. TIA!

You must be logged in to vote

Replies: 1 comment · 3 replies

Comment options

Many things that are not good :)

fastresume.bin only helps you if the target binary did not change - so was not recompiled sind the last run. otherwise it will detect there is a change and perform calibration - and ignore the data in fastresume.bin (it has to!).

also if you can use fastresume.bin, you cannot restart with additional new inputs.

IF the target binary did not change, and you want to restart AND add new seeds, then you just start normally with -i - to signal you want to restart, the fastresume.bin will be read, and the new seeds you just add via "afl-addseeds -i new_seeds_directory -o afl-fuzz-out-dir`.

But TLDR: fastresume.bin wont help you because of the target was recompiled, right?

Finally some words about Fuzzing in a CI. bad idea. usually a very bad idea.
why? because it might find crashes but the crashes might have nothing to do with the changes in a PR, developers hate that. Also because CI time is limited (the longer the longer the wait time until something can get merged - devs hate that too and are right about that).
Instead you fuzz independent from the CI, daily or weekly you rebuild the target for fuzzing, keep the corpus, add what needs to be added, and restart the fuzzer.

You must be logged in to vote
3 replies
@abhisen7
Comment options

Thanks @vanhauser-thc for clarifying about fastresume.bin, things are much clearer now.

About CI-Fuzzing, you are spot on about the PR blocking issue. The way things are set up now is to not run on every PR (because as you said- 1. it's time consuming, and 2. a crash may not be due to the PR commits). Instead, we do one daily scheduled run for 4 hours on master. That way, any crash due to fuzzing can be picked up by engineering on-call for debugging just like production issues or other test suites.

Another factor that led to CI-Fuzzing: Being a startup, engineering velocity is currently too fast, and therefore renders harness outdated pretty quickly. If anything is more frustrating that not finding bugs- it is harness that fails to build because something changes in the dependencies/target class every now and then. Hence, we are also planning to build the fuzz targets using ccache on every PR (but not fuzz them), so that if it fails to build, the dev knows it's prolly due to their changes and they can update the harness before the next CI-Fuzz run.

So tl;dr: Do you think it can slightly improve efficiency if we upload the queue at the end of every CI run, then on the next run, we merge it temporarily with the seed inputs (on the CI runner) and just let AFL++ run its course w/o bothering much about the state? The way I see it- if we seed with the queue data, we are also providing patterns that were mutated based on previous feedbacks so AFL++ is perhaps getting a leg up in the next cycle (in terms of finding those paths quickly). WDYT?

@vanhauser-thc
Comment options

Sounds like a good apporach to me, but why only fuzz for 4 hours instead of 23-24?
requiring a successful harness build in the CI is a very good idea.
Of course keep the generated corpus! do a minimization on the new compiled harness before you run and keep backups.
Also have a specific reviewer if the harness changes (because this can invalidate the existing corpus and if the change is good then you need a rewriter for the existing corpus)

@abhisen7
Comment options

4 hours because Github Actions limits self-hosted runner jobs to 6 hours. We are currently building harnesses w/o ccache, so factoring all the pre-fuzzer steps (deps installation + harness build) and post-fuzzing steps (crash detection + corpus and crash uploads), we are quite limited on the runtime. Guess once we turn on caching, we can bump that to 5 hours easy.

Thanks for reminding about corpus trimming, it def makes no sense to seed AFL++ with redundant test cases. Maybe I'll run afl-cmin on the downloaded queue (from prev run), redirect the output to the project seed corpus dir, which is then passed to AFL++ to start the fuzzing.

Regarding corpus maintenance, this is really another important aspect. Right now, we don't foresee a situation where a harness rewrite will completely make the existing seed useless. There are other interfaces we fuzz (like file format parsers) where corpus maintenance is really important and needs to be structured/maintained around the harness logic.

I am planning a fun PoC with LLMs to seed fuzzers on the fly, that will eliminate the onus of maintaining extensive corpuses at repo level. We could extend the wrapper script(s) that control the CI-fuzzing campaigns, to also generate LLM prompts for creating input seeds before starting the fuzzer. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
important a highly important issue
2 participants
Converted from issue

This discussion was converted from issue #2236 on November 07, 2024 13:25.

Morty Proxy This is a proxified and sanitized view of the page, visit original site.