AFLplusplus / AFLplusplus/AFLplusplus
Feature: Allow target to abort/cancel current test case
- 主要语言
- C
- 星标
- 6.8k
- 派生
- 1.3k
- 平均合并
- 3 小时 27 分钟
- 30 天内合并 PR
- 16
描述
# 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
- 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
1. 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.)
2. Do nothing and spend time pruning the invalid crashes after (this is my "current" solution and it's getting annoying).
3. 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.
4. 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.
5. 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.
6. 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)
- @domenukk
> 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
- @vanhauser-thc
# Questions
Any additional advice or warnings before I attempt this? :smiley:
贡献指南
评估
这个 Issue 还没有评估数据。