You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm currently taking advantage of the extremely fast speed of persistent qemu_mode to avoid forking or needing to reset the memory state (along with afl_persistent_hook to avoid I/O). (i.e. I only need to set AFL_QEMU_PERSISTENT_ADDR=0x1337aaaa.)
I'm fuzzing closed source libraries, and sometimes I do run into weird edge that require resetting the entire state (the most common being memory leaks). I have written a crash handler in my target itself that detects some of these edge cases (e.g. if OOM, just exit(0);).
Problem
The bigger issue is that AFL++ sees that it "found" a new path to my crash handler, and considers it to be a unique (A -> B -> C -> OOM handler is technically different than A -> B -> OOM handler). This usually isn't even reproducible, as running one small leaky test case by itself isn't going to cause an OOM crash.
Example Situation
Persistent iterations 1 to 5,000 run "fine", and leak a small amount of memory on each iteration (this is fine for now as I have enough memory)
Persistent iterations 5,000 to 9,998 run without issue
Persistent iteration 9,999 leaks a tons of memory, but does not quite crash
Persistent iteration 10,000 "crashes" on a OOM, because the previous iteration basically left us with no memory to use.
Possible Solutions
Use AFL_QEMU_PERSISTENT_MEM. This far from ideal, as in the example above I'd be unnecessarily wasting time resetting the memory state for problem that's only ruining ~0.01% of iterations. (My real world targets are well under <1% too, this isn't a theoretical situation.)
Do nothing and spend time pruning the invalid crashes after (this is my "current" solution and it's getting annoying).
Add new flags like AFL_VERIFY_CRASH and AFL_VERIFY_NEW_TESTCASE that would require AFL++ to rerun any testcases in a fresh state before saving or adding them to the queue.
Have the target raise an unused/"special" signal code (i.e. 32) that will cause AFL++ to consider the current test case iteration to be invalid and to restart.
Have the target use an unused/"special" exit code (i.e. 64) that will cause AFL++ to consider the current test case iteration to be invalid and to restart.
Implement a shared map that the target can use to notify AFL++ to consider the current test case iteration to be invalid and to restart.
Previous Discussions
I had asked in the Awesome Fuzzing Discord for advice back in November. Decided I should put here on GitHub so I don't lose track of it myself. =)
Based on the replies, I think we/I should implement solution 6?
Well the whole feedback reporting is using a shared map, you may be able to take some ideas from that, but the main communication with the forkserver is pipe-based. We try to not break the old protocol (afl++ targets and afl-fuzz are compatible, and vice versa)
yes this information should be transferred via the pipe.
not all afl++ targets are directly compatible with afl due to non-colliding. in that case config.h MAP_SIZE_POW2 has to be increased to match in afl variants
You can use signals.
AFL abort current queue if catch SIGUSR1.
Also, you can look how timedout queues are handled in AFL side.
Other way is reporting target IP at the moment of crash to AFL via pipe.
Adding to queue structure two new fields like 'crashed_times' and 'crashed_ip' should solve the problem.
Setup
I'm currently taking advantage of the extremely fast speed of persistent qemu_mode to avoid forking or needing to reset the memory state (along with afl_persistent_hook to avoid I/O). (i.e. I only need to set
AFL_QEMU_PERSISTENT_ADDR=0x1337aaaa
.)I'm fuzzing closed source libraries, and sometimes I do run into weird edge that require resetting the entire state (the most common being memory leaks). I have written a crash handler in my target itself that detects some of these edge cases (e.g. if OOM, just
exit(0);
).Problem
The bigger issue is that AFL++ sees that it "found" a new path to my crash handler, and considers it to be a unique (A -> B -> C -> OOM handler is technically different than A -> B -> OOM handler). This usually isn't even reproducible, as running one small leaky test case by itself isn't going to cause an OOM crash.
Example Situation
Possible Solutions
AFL_QEMU_PERSISTENT_MEM
. This far from ideal, as in the example above I'd be unnecessarily wasting time resetting the memory state for problem that's only ruining ~0.01% of iterations. (My real world targets are well under <1% too, this isn't a theoretical situation.)AFL_VERIFY_CRASH
andAFL_VERIFY_NEW_TESTCASE
that would require AFL++ to rerun any testcases in a fresh state before saving or adding them to the queue.Previous Discussions
I had asked in the Awesome Fuzzing Discord for advice back in November. Decided I should put here on GitHub so I don't lose track of it myself. =)
Based on the replies, I think we/I should implement solution 6?
Questions
Any additional advice or warnings before I attempt this? 😃
The text was updated successfully, but these errors were encountered: