AFLplusplus / AFLplusplus/AFLplusplus

Feature: Allow target to abort/cancel current test case

未关闭
#655 4 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
enhancement help wanted
主要语言
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 还没有评估数据。

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。