A working implementation of the AFL++ forkserver protocol for fuzzing Julia programs. This allows you to use AFL++ to find bugs in Julia code through coverage-guided fuzzing.
- ✅ Implements AFL++ new forkserver protocol (v1)
- ✅ Maps shared memory for coverage tracking
- ✅ Achieves ~30,000 executions per second
- ✅ Properly converts Julia exceptions to Unix signals
- ✅ No actual forking (runs in parent process for simplicity)
- AFL++ (tested with version 4.33c)
- Julia (tested with 1.10+)
- Linux (for shared memory IPC)
- Clone this repository:
git clone https://github.com/KenoAIStaging/julia-afl-forkserver.git
cd julia-afl-forkserver
- Create a simple fuzz target:
#!/usr/bin/env julia
include("afl_forkserver.jl")
function my_target(input::Vector{UInt8})
# Your code here - throw exceptions on errors
if length(input) >= 4 && input[1:4] == b"BOOM"
error("Found the bug!")
end
end
afl_main(my_target)
- Create input corpus:
mkdir corpus
echo "test" > corpus/seed.txt
- Run AFL++:
export AFL_SKIP_BIN_CHECK=1 # Required since Julia binary isn't instrumented
afl-fuzz -i corpus -o findings -- julia your_fuzzer.jl
The included example_fuzzer.jl
demonstrates a simple fuzzing target with intentional bugs:
# Test it standalone
echo "safe input" | julia example_fuzzer.jl
# Run with AFL++
afl-fuzz -i corpus -o findings -- julia example_fuzzer.jl
The implementation:
- Detects AFL++ via the
__AFL_SHM_ID
environment variable - Performs handshake using the new forkserver protocol:
- Sends version (AFL magic + v1)
- Receives XOR confirmation
- Exchanges options (map size)
- Sends final confirmation
- Maps shared memory for coverage tracking
- Executes targets in a loop without forking
- Reports crashes by mapping Julia exceptions to Unix signals
The trace()
function provides manual coverage tracking:
function my_target(input::Vector{UInt8})
trace(0x1000) # Mark entry
if some_condition
trace(0x2000) # Mark branch
# ...
end
trace(0x3000) # Mark exit
end
Main entry point. Pass your fuzzing target function that accepts Vector{UInt8}
.
Optional coverage tracking. Call at interesting points in your code.
In testing, this implementation achieved:
- ~30,000 executions per second
- Found 250 crashes in 60 seconds
- 0.60% bitmap coverage
- No actual forking (state persists between runs)
- Coverage data is minimal (not automatic)
- Requires
AFL_SKIP_BIN_CHECK=1
- Linux only (uses SysV IPC)
The implementation uses:
- File descriptors 198/199 for AFL++ communication
- SysV shared memory for coverage bitmap
- Julia's
ccall
for system calls - Exception mapping for crash detection
MIT License - See LICENSE file for details
Pull requests welcome! Please test with AFL++ before submitting.
- AFL++ team for the amazing fuzzer
- Julia community for the excellent language