Skip to content

Md Aeinul Islam - adaptive coverage - #4

Open
md-islam wants to merge 8 commits into
mainfrom
md-adaptive-coverage
Open

Md Aeinul Islam - adaptive coverage#4
md-islam wants to merge 8 commits into
mainfrom
md-adaptive-coverage

Conversation

@md-islam

@md-islam md-islam commented Dec 4, 2025

Copy link
Copy Markdown
Collaborator

summary

⏺ Adaptive coverage is a dynamic fuzzing strategy that automatically adjusts how much code coverage instrumentation
is used based on whether the fuzzer is actually finding new paths.

The core idea:

  • When the fuzzer is actively discovering new paths → Use 100% coverage (maximize exploration)
  • When discovery is slowing down → Drop to 50% coverage (balance speed and guidance)
  • When the fuzzer is stuck/stagnant → Drop to 25% coverage (prioritize throughput)

How it works:

  1. Track the time since the last new path was discovered
  2. Adjust coverage percentage based on three time thresholds:
    - < 5 minutes since new path → 100% coverage (HOT phase)
    - 5-30 minutes since new path → 50% coverage (WARM phase)
    - > 30 minutes since new path → 25% coverage (COLD phase)
  3. When a new path is found, reset the timer back to 100%

Why this matters:

  • Full coverage has ~2x overhead from instrumentation
  • Late in fuzzing campaigns, the fuzzer often gets stuck without finding new paths
  • Running full coverage while stuck wastes CPU cycles
  • By reducing coverage when stuck, you get faster execution (more test cases per second)
  • When progress resumes, coverage automatically scales back up

Key advantage over alternatives:

  • Marco's -F 50: Fixed 50% always - doesn't adapt to progress
  • Leo's hybrid: Switches once at a fixed time - not continuous
  • Your adaptive -A: Continuously responds to actual fuzzing progress

It's basically saying: "Use expensive coverage when it's working, cheap coverage when you're stuck."

⏺ # Add Adaptive Coverage Mode for AFL++

Summary

Implements adaptive coverage mode - a dynamic coverage adjustment strategy that automatically scales
instrumentation based on fuzzing progress.

Motivation

Coverage overhead remains constant throughout fuzzing campaigns, even when path discovery stagnates. This wastes
resources during late-stage fuzzing when the fuzzer is stuck and not finding new paths.

Problem: Full coverage has ~2x overhead even when discovery has stopped.

Solution: Dynamically adjust coverage based on time since last new path discovery.

Implementation

Algorithm

Coverage adjusts automatically in three tiers based on fuzzing progress:

Time Since New Path Coverage % Phase Rationale
< 5 minutes 100% HOT Active discovery - maximize exploration
5-30 minutes 50% WARM Declining discovery - balance speed/guidance
> 30 minutes 25% COLD Stagnation - prioritize throughput

Key Features

  • Zero configuration - Automatically adapts to target difficulty
  • Single binary - No dual compilation needed
  • Minimal changes - 55 lines across 3 files
  • Clean integration - Builds on existing -F flag infrastructure

Usage

# Enable adaptive mode
afl-fuzz -A -i seeds -o output -- ./target @@

# With debug output to see transitions
AFL_DEBUG_ADAPTIVE=1 afl-fuzz -A -i seeds -o output -- ./target @@

Example Output

[ADAPT] Time since new path: 120000 ms, coverage: 100%   ← Finding paths
[ADAPT] Time since new path: 400000 ms, coverage: 50%    ← Slowing down
[ADAPT] Time since new path: 1900000 ms, coverage: 25%   ← Stuck
[ADAPT] Time since new path: 30000 ms, coverage: 100%    ← New path! Reset

Technical Details

Files Modified

1. include/afl-fuzz.h (6 lines)
  - Add state variables to afl_state_t structure
2. src/afl-fuzz.c (44 lines)
  - Implement adjust_adaptive_coverage() function
  - Add -A flag parsing
  - Call adjustment before seed selection
  - Add help text
3. src/afl-fuzz-bitmap.c (5 lines)
  - Track timestamp when new paths discovered
  - Reset timer on progress

Total: 55 lines added, 0 removed

How It Works

// 1. Track when new path found
if (new_path_discovered) {
    last_new_path_time = get_cur_time();
}

// 2. Adjust coverage before each seed
time_elapsed = now() - last_new_path_time;

if (time_elapsed < 300000)       // 5 min
    coverage = 100%;
else if (time_elapsed < 1800000) // 30 min
    coverage = 50%;
else
    coverage = 25%;

// 3. Integrate with existing infrastructure
feedback_use_pct = coverage;  // Marco's variable

Integration

Builds on Marco's percentage-based infrastructure:
- Uses existing feedback_use_pct variable
- Leverages set_feedback_for_current_seed() logic
- No duplication - clean integration

Expected Benefits

Hypotheses:
- Maintain ≥90% bug-finding effectiveness vs. 100% coverage
- Achieve 1.5-3x average throughput improvement
- Outperform any fixed percentage strategy on diverse targets

Why:
- Full coverage when productive (early discovery phase)
- Reduced overhead when stagnating (late campaign)
- Automatically adapts to target difficulty

Comparison with Other Approaches

| Approach      | Strategy              | Flexibility |
|---------------|-----------------------|-------------|
| Baseline      | 100% always           | None        |
| Marco's -F 50 | Fixed 50%             | Static      |
| Leo's Hybrid  | Switch at 30% of time | One-time    |
| Adaptive -A   | 100% → 50% → 25%      | Continuous  |

Advantages:
- ✅ No manual tuning required
- ✅ Responds to actual progress, not fixed schedule
- ✅ Single binary deployment
- ✅ Simple usage (just add -A)

Testing

Ready for validation:
- Code compiles
- Integrates with existing AFL++ infrastructure
- Local testing on simple target
- MAGMA benchmark evaluation (10-hour campaigns)
- Statistical comparison vs. baseline

Commits

3 logical commits:

1. c978e4ab - Add adaptive coverage mode state variables
2. a4c8efcd - Implement adaptive coverage adjustment and -A flag
3. a5b49a02 - Track new path discovery timestamps

Progression: State → Logic → Integration

Related Work

This approach complements existing coverage reduction strategies:
- UnTracer-AFL - Dual-binary oracle/tracer (different signal)
- Marco's -F - Fixed percentage (static)
- Leo's Hybrid - Scheduled switch (predetermined)

Novel contribution: Temporal adaptation based on actual fuzzing progress.

Future Work

Possible extensions:
- Tunable thresholds via environment variables
- More granular tiers (5 levels instead of 3)
- Per-seed adaptive coverage
- Machine learning for threshold selection

Checklist

- Code compiles without errors
- Minimal, focused changes
- Integrates with existing infrastructure
- Debug mode included
- Help text updated
- Clean commit history
- Experimental validation

Author

MD Aeinul Islam
- Implementation: Adaptive coverage algorithm
- Research: Related work analysis (UnTracer, Angora)
- Integration: Built on Marco's -F flag infrastructure

---
Ready to merge pending experimental validation on MAGMA benchmark.

mdrovell and others added 6 commits December 1, 2025 03:44
Specify FUZZ_PCT=[0,100] in configrc before running run.sh.
You may check whether it works by looking at the buildlog's docker run command, whether there is an -env=FUZZ_PCT=

See #3

Co-authored-by: zlzcty <zlzcty@me.com>
Add fields to afl_state_t structure to support adaptive coverage:
- adaptive_mode: flag to enable/disable adaptive mode
- last_new_path_time: timestamp of last new path discovery
- time_since_new_path: calculated elapsed time
- adaptive_cov_pct: current coverage percentage

These variables will enable dynamic coverage adjustment based
on fuzzing progress, inspired by Angora's selective instrumentation
principle but using a temporal signal instead of per-execution detection.
Add adjust_adaptive_coverage() function implementing three-tier algorithm:
- Tracks time since last new path discovery
- Adjusts coverage: 100% (hot) → 50% (warm) → 25% (cold)
- Integrates with Marco's feedback_use_pct infrastructure

Add -A command-line flag to enable adaptive mode:
- Initializes adaptive state variables
- Sets starting coverage to 100%
- Displays confirmation message

Add help text documenting -A flag usage.

Temporal adaptation inspired by Angora's selective instrumentation
principle but implemented in single binary for simpler deployment.
Update last_new_path_time when add_to_queue() is called.
This resets the adaptive timer, causing coverage to return to 100%
when fuzzer makes progress.

Integration point follows Angora's pattern of detecting coverage-
increasing executions, but uses timestamp tracking instead of
dual-binary oracle/tracer approach for simpler implementation.
@md-islam md-islam changed the title Md adaptive coverage Md Aeinul Islam - adaptive coverage Dec 4, 2025
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.

5 participants