- docs/internal/symex-fuzz-landscape.md: 11 tools across 6 categories - tools/fold-swift/swan_sil_parser: 75 SIL operator kinds, JSON converter - bench/juliet/expansion/: 118-CWE catalog, gold generator, runner - bench/score_fp.py: precision/recall/F1 per detector
863 lines
37 KiB
Markdown
863 lines
37 KiB
Markdown
# Symbolic Execution + Fuzzing Tools Landscape
|
|
|
|
> Architecture expansion research for fold. Generated 2026-05-27.
|
|
|
|
Maps the symbolic execution, model checking, abstract interpretation, and
|
|
fuzzing tools relevant to fold's multi-language expansion across C++, Rust,
|
|
Swift, and binary targets. For each tool: approach, IR level, language
|
|
support, false-positive profile, maturity, and concrete integration pattern
|
|
for fold.
|
|
|
|
## Table of contents
|
|
|
|
1. [Taxonomy](#taxonomy)
|
|
2. [Symbolic execution engines](#symbolic-execution-engines)
|
|
3. [Model checkers & verifiers](#model-checkers--verifiers)
|
|
4. [Abstract interpreters](#abstract-interpreters)
|
|
5. [Fuzzing engines](#fuzzing-engines)
|
|
6. [Binary analysis frameworks](#binary-analysis-frameworks)
|
|
7. [Integration pattern catalog](#integration-pattern-catalog)
|
|
8. [Architecture expansion recommendations](#architecture-expansion-recommendations)
|
|
|
|
---
|
|
|
|
## Taxonomy
|
|
|
|
| Approach | What it does | fold already does it? |
|
|
|----------|-------------|----------------------|
|
|
| **Symbolic execution** | Tracks symbolic values along paths, queries SMT at branches | Yes — Z3 BV-64 encoder, per-sink SAT queries |
|
|
| **Concrete fuzzing** | Mutates byte inputs, runs target natively, reports crashes | Yes — libFuzzer/AFL++ via `fold fuzz-run` |
|
|
| **Concolic execution** | Concrete execution + parallel symbolic shadow store, negate branches | Planned — M31 Phase 3 (LibAFL+symcc-rt) |
|
|
| **Model checking** | Encode full program + property as SMT formula; prove or find counterexamples | No — fold is per-function, not whole-program BMC |
|
|
| **Abstract interpretation** | Fixed-point over abstract domains (intervals, octagons, polyhedra) | Partial — interval pre-pass, no AI fixpoint engine |
|
|
| **Binary analysis** | Disassemble + lift to IR for pattern/heuristic detection | Yes — R2Backend for strings/symbols/calls/xrefs |
|
|
|
|
---
|
|
|
|
## Symbolic execution engines
|
|
|
|
### KLEE
|
|
|
|
| Dimension | Detail |
|
|
|-----------|--------|
|
|
| **Approach** | Full symbolic execution |
|
|
| **IR level** | LLVM IR (bitcode) |
|
|
| **Languages** | C, C++ (any language that compiles to LLVM IR) |
|
|
| **Solver** | KLEE's own constraint solver + Z3 backend |
|
|
| **FP rate** | Low — explores actual paths. Missing code produces false negatives, not false positives. |
|
|
| **Maturity** | Very high. 15+ years. Active maintenance (KLEE 3.1, 2024). SV-COMP participant. |
|
|
| **License** | GPL-2.0 (with LLVM exception for the ucKLEE variant) |
|
|
| **Key capability** | Bottom-up path exploration from a harness entry point. Produces high-quality test inputs for every covered path. Symbolic filesystem, POSIX environment models. |
|
|
|
|
**How it works:**
|
|
|
|
KLEE interprets LLVM bitcode symbolically. Memory is a flat symbolic array with
|
|
byte-level granularity. At branches, KLEE forks the state and adds the branch
|
|
condition to each path's constraint set. When a path terminates, KLEE concretizes
|
|
the symbolic input to produce a test case. KLEE's constraint solver layer
|
|
(KQuery → STP/Z3) optimizes for the pattern-matching checks common in path
|
|
exploration.
|
|
|
|
**Integration pattern for fold:**
|
|
|
|
The license mismatch (GPL-2.0 vs fold's planned GPL-3.0) is noted in
|
|
`docs/internal/m31-phase3-concolic.md` and is the primary reason fold deferred
|
|
KLEE adoption. Architectural mismatch too: KLEE owns the process (its own
|
|
interpreter loop), while fold orchestrates child processes via `posix_spawn`.
|
|
|
|
If fold's license posture changes, a useful integration would be:
|
|
|
|
```
|
|
fold scan → findings with Z3 witnesses
|
|
↓
|
|
fold fuzz-prep → emit KLEE harness (.c file calling target function)
|
|
↓
|
|
klee --libc=uclibc --posix-runtime harness.bc
|
|
↓
|
|
fold fuzz-ingest ← KLEE test cases → ConcreteWitness promotion
|
|
```
|
|
|
|
KLEE's strength — exhaustive bounded path coverage from an entry point —
|
|
complements fold's per-sink SAT approach. KLEE could confirm that a
|
|
fold-flagged sink is actually reachable from a program entry point, closing
|
|
fold's "SAT under our encoding but maybe unreachable" gap.
|
|
|
|
**Relevance to fold:** Medium. The license barrier is real. The architectural
|
|
mismatch (KLEE as interpreter, fold as orchestrator) means integration would be
|
|
a side-by-side pipeline, not an embedded pass. Worth reconsidering if fold
|
|
adds a verification tier (e.g., CBMC-style whole-module bounded verification)
|
|
where KLEE's path coverage complements fold's bottom-up scan.
|
|
|
|
---
|
|
|
|
### Haybale
|
|
|
|
| Dimension | Detail |
|
|
|-----------|--------|
|
|
| **Approach** | Symbolic execution |
|
|
| **IR level** | LLVM IR (via `llvm-ir` crate) |
|
|
| **Languages** | Any language with LLVM bitcode (practically: C, C++, Rust via `--emit=llvm-ir`) |
|
|
| **Solver** | Boolector (default), Z3 (optional backend) |
|
|
| **FP rate** | Very low — full path exploration, well-defined memory model. |
|
|
| **Maturity** | Research-grade. Last major release 2021. Trail of Bits project, not actively maintained. |
|
|
| **License** | MIT / Apache-2.0 |
|
|
| **Key capability** | Pure Rust symbolic execution for LLVM IR. Clean API for programmatic path exploration, hookable function models, and SMT query callback. |
|
|
|
|
**How it works:**
|
|
|
|
Haybale is a Rust library that loads LLVM bitcode and provides a symbolic
|
|
execution engine. It uses Boolector (a bitvector SMT solver, also from the
|
|
Boolector/STP/KLEE lineage) for constraint solving. The API is designed for
|
|
embedding: you write a Rust program that uses Haybale to explore specific
|
|
functions. Haybale handles memory as a flat byte-addressable array, models
|
|
LLVM instructions symbolically, and provides hooks for modeling library
|
|
functions.
|
|
|
|
**Integration pattern for fold:**
|
|
|
|
Haybale's Rust-native design and permissive license make it the most
|
|
architecturally natural symbolic execution backend for fold's Rust expansion.
|
|
Integration shape:
|
|
|
|
```
|
|
fold scan --mode rust <crate>
|
|
↓
|
|
fold-rust extract → NDJSON (IR + findings)
|
|
↓
|
|
fold-concolic (Rust crate) → Haybale Project::from_bc_path()
|
|
↓ ↓
|
|
target_fn.bc ← rustc --emit=llvm-ir symbolically_execute_fn()
|
|
↓
|
|
path constraints → Boolector/Z3 → new seeds → libFuzzer corpus
|
|
```
|
|
|
|
Haybale could serve as fold's Rust-native answer to the C++ side's
|
|
symcc-rt + LibAFL concolic bridge. Because Haybale is a library (not a
|
|
process), it avoids the subprocess IPC overhead. It also avoids the
|
|
license problem KLEE has.
|
|
|
|
**Relevance to fold:** High for the Rust frontend specifically. Haybale
|
|
provides symbolic execution for LLVM IR from a Rust host — exactly what
|
|
a `fold-concolic` Rust crate would need to do path exploration on
|
|
Rust-generated bitcode. The lack of active maintenance is a risk, but
|
|
for fold's bounded-model use case (not full-system symbolic execution),
|
|
the existing codebase may be sufficient. Evaluate in a spike: can Haybale
|
|
load and symbolically execute the bitcode from a `fold-rust extract`
|
|
target in under 100 lines of integration code?
|
|
|
|
---
|
|
|
|
## Model checkers & verifiers
|
|
|
|
### Kani
|
|
|
|
| Dimension | Detail |
|
|
|-----------|--------|
|
|
| **Approach** | Bounded model checking (CBMC-based) |
|
|
| **IR level** | Rust MIR → GOTO intermediate representation → SMT |
|
|
| **Languages** | Rust |
|
|
| **Solver** | CBMC's built-in SMT pipeline (Z3, MathSAT, CVC5 backends) |
|
|
| **FP rate** | Very low (sound for the bound chosen). Properties are proved, not guessed. |
|
|
| **Maturity** | High. AWS-backed, active development (2024 releases). Growing adoption in safety-critical Rust. |
|
|
| **License** | MIT / Apache-2.0 |
|
|
| **Key capability** | Verify Rust programs against user-written `#[kani::proof]` harnesses. Prove absence of panics, overflows, and user-specified assertions within a bounded unrolling depth. |
|
|
|
|
**How it works:**
|
|
|
|
Kani compiles Rust MIR into CBMC's GOTO intermediate representation, then
|
|
runs CBMC's bounded model checker on the result. Users write proof harnesses
|
|
annotated with `#[kani::proof]` and `kani::assume()`/`kani::assert()`.
|
|
Kani then verifies (proves or finds counterexamples for) those harnesses.
|
|
The result is either a proof (no property violation within the unrolling
|
|
bound) or a concrete counterexample trace.
|
|
|
|
Kani is verification, not scanning: it proves properties of specific harnesses,
|
|
not "find all bugs in this codebase."
|
|
|
|
**Integration pattern for fold:**
|
|
|
|
Kani occupies a different niche than fold (verification vs scanning), but
|
|
they compose well:
|
|
|
|
```
|
|
fold scan --detectors security → findings for Rust unsafe blocks
|
|
↓
|
|
For each high-confidence finding:
|
|
↓
|
|
fold emit-kani-proof → generate #[kani::proof] harness for the flagged function
|
|
↓
|
|
cargo kani --harness <name>
|
|
↓
|
|
├─ VERIFIED → fold finding downgraded to "Kani-proved unreachable"
|
|
└─ FAILED → Concrete counterexample → fold promotes to ConcreteWitness
|
|
```
|
|
|
|
Fold adds bottom-up scanning ("find plausible bugs") and Kani adds
|
|
top-down verification ("prove this specific property"). Fold's per-sink
|
|
SAT queries find candidates; Kani's whole-program BMC confirms or refutes
|
|
them with higher confidence.
|
|
|
|
The integration is straightforward because both tools work with Rust's
|
|
MIR (fold-rust via `rustc_driver` → HIR; Kani via `kani-compiler` →
|
|
GOTO). A `fold emit-kani-proof` command that generates Kani harnesses
|
|
from fold's Rust findings would be a ~200-line addition to
|
|
`tools/fold-rust/`.
|
|
|
|
**Relevance to fold:** High for the Rust expansion's confidence pipeline.
|
|
Kani provides the verification tier fold's Rust side currently lacks
|
|
(all Rust findings are `Heuristic` today). A fold→Kani bridge would
|
|
promote some findings to "verified unreachable" and others to
|
|
"concrete counterexample" — the same closed loop the C++ side achieves
|
|
with Z3→libFuzzer→ConcreteWitness.
|
|
|
|
---
|
|
|
|
### Rudra
|
|
|
|
| Dimension | Detail |
|
|
|-----------|--------|
|
|
| **Approach** | Static analysis (pattern-matching + dataflow) |
|
|
| **IR level** | Rust MIR (via `rustc` plugin, now deprecated) and HIR |
|
|
| **Languages** | Rust |
|
|
| **FP rate** | Low for unsafe-API patterns; moderate on send/sync inference. |
|
|
| **Maturity** | Research project (Georgia Tech, 2020-2021). Deprecated as of 2023 — the `rustc` plugin API it used is removed. |
|
|
| **License** | MIT |
|
|
| **Key capability** | Found 76 CVEs and 112 RustSec advisories in the Rust ecosystem. Pioneered systematic unsafe-block auditing at ecosystem scale. |
|
|
|
|
**How it works:**
|
|
|
|
Rudra ran as a `rustc` plugin (before the plugin API was removed) and analyzed
|
|
Rust MIR for three classes of bugs: (1) unsafe API misuse (e.g., `Vec::from_raw_parts`
|
|
with untrusted lengths), (2) incorrect `Send`/`Sync` implementations leaking
|
|
interior mutability, and (3) panic safety violations in unsafe code. The analysis
|
|
was primarily pattern-matching over MIR combined with limited dataflow.
|
|
|
|
**Why Rudra is listed even though deprecated:**
|
|
|
|
Rudra's detector catalog — the specific patterns it flagged — is a design
|
|
blueprint for fold-rust's security detectors. Rudra proved these patterns
|
|
have high yield in real-world Rust code (112 advisories). fold-rust can
|
|
re-implement the same patterns as HIR visitors in `tools/fold-rust/src/`.
|
|
|
|
**Integration pattern for fold:**
|
|
|
|
Rudra is a source of detector ideas, not a runtime to integrate:
|
|
|
|
```
|
|
Rudra's detector catalog → fold-rust HIR visitors:
|
|
Send/Sync inference ↓
|
|
unsafe API patterns ↓
|
|
panic safety ↓
|
|
→ fold-rust finding_kind: rust-unsafe-api
|
|
```
|
|
|
|
fold-rust already has the `rust-unsafe-api` and `rust-unchecked-index`
|
|
finding kinds (`include/fold/report/finding.hpp`). Rudra's specific
|
|
patterns (e.g., "`Vec::from_raw_parts` with untrusted `capacity`") should
|
|
be added as rules under those kinds. This is a detector-authoring task
|
|
within fold-rust, not a tool integration.
|
|
|
|
**Relevance to fold:** Medium (as a detector catalog). Rudra's 112-advisory
|
|
track record makes it the strongest source of real-world Rust unsafe
|
|
patterns. fold-rust's `DerefHunter` covers raw-pointer derefs; adding
|
|
Rudra's send/sync and unsafe-API patterns would make fold-rust a
|
|
genuine Rust SAST rather than a single-detector tool.
|
|
|
|
---
|
|
|
|
### MIRAI
|
|
|
|
| Dimension | Detail |
|
|
|-----------|--------|
|
|
| **Approach** | Abstract interpretation |
|
|
| **IR level** | Rust MIR |
|
|
| **Languages** | Rust |
|
|
| **FP rate** | Moderate — abstract interpretation over-approximates; many "maybe" results. |
|
|
| **Maturity** | Research project (Facebook/Meta, 2019-2023). Not actively maintained as of 2024. |
|
|
| **License** | MIT |
|
|
| **Key capability** | Taint tracking, integer overflow detection, unreachable code detection. Abstract domain with widening on MIR. |
|
|
|
|
**How it works:**
|
|
|
|
MIRAI runs as a `rustc` driver (similar to fold-rust's architecture) and
|
|
lifts Rust MIR into an abstract interpreter. It tracks integer ranges
|
|
(via intervals + widening) and taint, flagging potential panics,
|
|
overflows, and unreachable code. Unlike Kani (which does bounded model
|
|
checking), MIRAI does abstract interpretation: it computes a fixpoint
|
|
over abstract domains and reports when the abstract state indicates a
|
|
possible problem.
|
|
|
|
**Integration pattern for fold:**
|
|
|
|
MIRAI's abstract interpreter is conceptually similar to fold's interval
|
|
pre-pass (`src/symbolic/` interval analysis), but applied at the MIR
|
|
level for Rust. Direct integration is impractical (MIRAI is unmaintained
|
|
research code). However, the architectural lesson is valuable:
|
|
|
|
```
|
|
MIRAI-style abstract domain → fold-rust MIR visitor (future)
|
|
Interval domain → refine Heuristic findings with range constraints
|
|
Taint domain → feed fold's taint-track detector on Rust
|
|
Layout domain → prove pointer provenance at compile time
|
|
```
|
|
|
|
fold-rust currently operates at the HIR level (via `rustc_driver` +
|
|
`rustc_hir`). To match MIRAI's precision, fold-rust would need a MIR
|
|
visitor for the abstract domains. The existing HIR infrastructure
|
|
(`DerefHunter`) works for syntactic patterns; MIR adds type resolution
|
|
after monomorphization, which is necessary for range analysis.
|
|
|
|
**Relevance to fold:** Medium (architectural lesson). MIRAI proves that
|
|
abstract interpretation on Rust MIR is practical and can find real bugs.
|
|
fold-rust should plan a MIR visitor layer for future precision upgrades
|
|
(RF-3b already calls this out: "move to MIR + monomorphization context").
|
|
MIRAI is the prior art that demonstrates it works.
|
|
|
|
---
|
|
|
|
### Miri
|
|
|
|
| Dimension | Detail |
|
|
|-----------|--------|
|
|
| **Approach** | MIR interpreter (concrete execution, not symbolic) |
|
|
| **IR level** | Rust MIR |
|
|
| **Languages** | Rust |
|
|
| **FP rate** | Essentially zero — detects actual UB at runtime on concrete inputs. False *negatives* possible (input-dependent). |
|
|
| **Maturity** | Very high. Official Rust project, shipped via `rustup +nightly component add miri`. Actively maintained. |
|
|
| **License** | MIT / Apache-2.0 |
|
|
| **Key capability** | Detects undefined behavior in Rust (including unsafe code) by interpreting MIR with UB checks. Stacked Borrows model for pointer provenance. |
|
|
|
|
**How it works:**
|
|
|
|
Miri interprets Rust MIR directly instead of compiling to machine code.
|
|
During interpretation, it checks for UB: out-of-bounds accesses, use-after-free,
|
|
data races, invalid pointer dereferences, and violations of the Stacked Borrows
|
|
aliasing model. Miri is a concrete interpreter — it runs a single execution path
|
|
with concrete inputs. It does not do symbolic execution or path exploration.
|
|
|
|
**Integration pattern for fold:**
|
|
|
|
Miri is a runtime checker, not a static analyzer, but it's fold's most natural
|
|
Rust validation tier — analogous to ASan on the C++ side:
|
|
|
|
```
|
|
fold scan --mode rust → findings (Heuristic confidence)
|
|
↓
|
|
fold fuzz-prep → generate Rust harness with concrete seeds
|
|
↓
|
|
MIRIFLAGS="-Zmiri-disable-isolation" cargo +nightly miri test
|
|
↓
|
|
├─ UB detected → fold finding promoted to ConcreteWitness
|
|
└─ Clean run → finding remains Heuristic (unconfirmed)
|
|
```
|
|
|
|
The integration is simpler than Kani: fold's `fuzz-prep` already generates
|
|
C harnesses (for libFuzzer+ASan). A Rust variant would generate `#[test]`
|
|
functions with `miri` cfg-gating, and fold's runner would shell out to
|
|
`cargo +nightly miri test` instead of compiling + running a libFuzzer binary.
|
|
|
|
Miri also integrates with cargo-fuzz: `cargo fuzz` targets can run under
|
|
`cargo +nightly miri run` for fast UB detection on small inputs before a
|
|
full fuzzing campaign. fold's Rust fuzz-prep could emit fuzz targets that
|
|
are Miri-compatible from day one.
|
|
|
|
**Relevance to fold:** Very high for Rust validation. Miri is the Rust
|
|
ecosystem's gold standard for UB detection, comparable in authority to
|
|
ASan+UBSan for C++. Every fold Rust finding that passes through a Miri
|
|
check and produces a UB trace is a `ConcreteWitness` with the same
|
|
authority as an ASan crash on the C++ side.
|
|
|
|
---
|
|
|
|
## Swift tools
|
|
|
|
### SWAN (Swift ANalysis)
|
|
|
|
| Dimension | Detail |
|
|
|-----------|--------|
|
|
| **Approach** | Static analysis framework |
|
|
| **IR level** | Swift SIL (Swift Intermediate Language) |
|
|
| **Languages** | Swift |
|
|
| **FP rate** | Depends on detector. SWAN is a framework; individual analyses vary. |
|
|
| **Maturity** | Research project (University of Bremen, 2018-2023). SWAN 2.0 added SIL support. Not actively maintained. |
|
|
| **License** | MIT |
|
|
| **Key capability** | Taint analysis framework for Swift. SIL-level analysis with configurable sources/sinks, framework for writing custom detectors. |
|
|
|
|
**How it works:**
|
|
|
|
SWAN is a static analysis framework built on top of the Swift compiler.
|
|
It operates at the SIL level and provides taint analysis infrastructure:
|
|
users define taint sources, propagation rules, sanitizers, and sinks.
|
|
SWAN then computes TaintFlows through the program. Initially operated
|
|
on the AST; SWAN 2.0 shifted to SIL for better precision.
|
|
|
|
**Integration pattern for fold:**
|
|
|
|
SWAN is directly relevant to `tools/fold-swift/` (Task 73 in the current
|
|
sprint). The integration pattern:
|
|
|
|
```
|
|
Swift .swift → swiftc -emit-sil → .sil file
|
|
↓ ↓
|
|
fold-swift → parses SIL SWAN → TaintFlows
|
|
↓ ↓
|
|
fold-swift detectors: fold-swift taint detector:
|
|
- unsafe cast patterns ← - taint config from SWAN's source/sink catalog
|
|
- force-unwrap detection - flow paths from SWAN's propagation model
|
|
- raw pointer derefs
|
|
↓
|
|
NDJSON findings → fold RustBackend → SARIF/JSON report
|
|
```
|
|
|
|
SWAN provides two things fold-swift needs:
|
|
1. **A proven taint framework for SIL** — the source/sink/sanitizer model
|
|
already works for Swift.
|
|
2. **A detector catalog** — SWAN ships with detectors for common Swift
|
|
security patterns (sensitive data leaks, injection, path traversal).
|
|
|
|
fold-swift can either:
|
|
- (A) Shell out to SWAN as a subprocess (SWAN → TaintFlow JSON → fold finding),
|
|
matching fold-rust's subprocess model.
|
|
- (B) Re-implement SWAN's taint propagation in fold-swift's own SIL visitor
|
|
(more work, but avoids an external dependency).
|
|
|
|
Option A is preferred for speed; option B for long-term maintenance. The
|
|
immediate path: shell out to SWAN for taint, add fold-swift's own SIL
|
|
visitors for pattern-matching detectors (unsafe casts, force-unwrap,
|
|
raw pointer access).
|
|
|
|
**Relevance to fold:** High for the Swift frontend. SWAN is the only
|
|
existing open-source taint framework for Swift SIL, and it's MIT-licensed.
|
|
It fills the taint-tracking gap fold-swift would otherwise have to build
|
|
from scratch.
|
|
|
|
---
|
|
|
|
## Fuzzing engines
|
|
|
|
### AFL++
|
|
|
|
| Dimension | Detail |
|
|
|-----------|--------|
|
|
| **Approach** | Coverage-guided greybox fuzzing |
|
|
| **IR level** | Source-level instrumentation (compiler pass) OR binary-level (QEMU, Unicorn) |
|
|
| **Languages** | C, C++, Rust (via cargo-afl), any binary |
|
|
| **Solver** | None — pure mutation-based with coverage feedback |
|
|
| **FP rate** | Near-zero — crashes are real. But false negatives (missed bugs) are inherent in fuzzing. |
|
|
| **Maturity** | Very high. Primary fuzzing engine in the AFL lineage. Active maintenance (2025 releases). |
|
|
| **License** | Apache-2.0 |
|
|
| **Key capability** | Industry-standard fuzzer. Custom mutators, persistent mode, binary-only fuzzing, LibAFL framework for custom fuzzing pipelines. |
|
|
|
|
**How it works:**
|
|
|
|
AFL++ instruments the target (at compile time or binary level) to track
|
|
edge coverage. It maintains a corpus of interesting inputs and repeatedly
|
|
mutates them, keeping inputs that discover new coverage edges. Forkserver
|
|
mode (or persistent mode) avoids process startup overhead. Binary-only
|
|
mode uses QEMU user-mode emulation with coverage instrumentation.
|
|
|
|
**Integration pattern for fold:**
|
|
|
|
fold already uses AFL++-adjacent patterns via libFuzzer and is planning
|
|
LibAFL adoption for M31 Phase 3. Specific integration points:
|
|
|
|
```
|
|
fold fuzz-run currently: libFuzzer + ASan
|
|
↓
|
|
fold fuzz-run future: LibAFL + libFuzzer (configurable backend)
|
|
↓
|
|
fold binary-fuzz-prep: AFL++ QEMU mode for Mach-O/ELF binaries
|
|
↓
|
|
fold binary-fuzz-run: AFL++ -Q (QEMU mode) or LibAFL binary-only
|
|
```
|
|
|
|
For fold's binary analysis path (`R2Backend`), AFL++ is the primary
|
|
fuzzing runtime. fold's `docs/internal/binary-fuzz-corpus.md` already
|
|
documents the dlopen harness pattern; AFL++'s QEMU mode would allow
|
|
fuzzing binaries without source access — a natural complement to
|
|
fold's r2-based binary string/symbol detectors.
|
|
|
|
**Relevance to fold:** High. AFL++ (via LibAFL) is fold's planned concolic
|
|
runtime (M31 Phase 3). AFL++ QEMU mode fills the binary fuzz gap
|
|
currently occupied by the unimplemented `fold binary-fuzz-prep` path.
|
|
AFL++ custom mutators could consume fold's Z3-derived dictionaries
|
|
(already emitted by `src/fuzz/dict_miner.cpp`).
|
|
|
|
---
|
|
|
|
### libFuzzer
|
|
|
|
| Dimension | Detail |
|
|
|-----------|--------|
|
|
| **Approach** | Coverage-guided in-process fuzzing |
|
|
| **IR level** | Source-level (compiled with `-fsanitize=fuzzer`) |
|
|
| **Languages** | C, C++ (LLVM toolchain) |
|
|
| **Solver** | None — mutation-based |
|
|
| **FP rate** | Near-zero for crashes; coverage gaps are false negatives |
|
|
| **Maturity** | Very high. Part of LLVM. Stable and well-documented. |
|
|
| **License** | Apache-2.0 (LLVM) |
|
|
| **Key capability** | In-process, fast, tightly integrated with ASan/UBSan/MSan. Data-flow-guided mutations (`-use_value_profile=1`). |
|
|
|
|
**How it works:**
|
|
|
|
libFuzzer is an in-process, coverage-guided fuzzer. The user writes
|
|
`LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)` and links
|
|
with `-fsanitize=fuzzer`. libFuzzer takes over `main()`, maintains a
|
|
corpus, mutates inputs (with coverage feedback), and reports crashes
|
|
to ASan. It's single-process and uses `fork()` only when requested.
|
|
|
|
**Integration pattern for fold:**
|
|
|
|
fold's tightest integration is with libFuzzer — it's already shipped
|
|
in M31 Phase 1+2 (`src/fuzz/`):
|
|
|
|
```
|
|
fold fuzz-prep → emits:
|
|
├─ harness.c (LLVMFuzzerTestOneInput calling target function)
|
|
├─ seed_corpus/ (Z3-derived witness bytes)
|
|
├─ dictionaries/ (libFuzzer dict from Z3 model constants)
|
|
└─ param_schema.h (struct layout for parameter passing)
|
|
|
|
fold fuzz-run → compiles harness + runs libFuzzer → ingest crashes → ConcreteWitness
|
|
```
|
|
|
|
fold's harness emitter (`src/fuzz/harness_emitter.cpp`) already
|
|
generates libFuzzer-compatible harnesses. The fuzz runner
|
|
(`src/fuzz/runner.cpp`) shells out to clang for compilation and
|
|
orchestrates libFuzzer campaigns.
|
|
|
|
**Relevance to fold:** Already integrated. libFuzzer is fold's
|
|
primary fuzzing backend. The M31 Phase 3 plan may supplement it
|
|
with LibAFL for concolic tracing, but libFuzzer remains the
|
|
default for simple coverage-guided fuzzing.
|
|
|
|
---
|
|
|
|
### cargo-fuzz
|
|
|
|
| Dimension | Detail |
|
|
|-----------|--------|
|
|
| **Approach** | Coverage-guided fuzzing (wraps libFuzzer) |
|
|
| **IR level** | Rust source → LLVM IR → libFuzzer |
|
|
| **Languages** | Rust |
|
|
| **Solver** | None |
|
|
| **FP rate** | Near-zero for crashes |
|
|
| **Maturity** | High. Official Rust fuzzing tool. Maintained by rust-fuzz team. |
|
|
| **License** | MIT / Apache-2.0 |
|
|
| **Key capability** | `cargo fuzz init` scaffolds a fuzz target; `cargo +nightly fuzz run` builds + runs. Integrates with ASan, `cargo-fuzz` also supports structure-aware fuzzing via `arbitrary`. |
|
|
|
|
**How it works:**
|
|
|
|
`cargo fuzz` is a Rust build-system wrapper around libFuzzer. It generates
|
|
fuzz targets (Rust source files with `fuzz_target!()` macro), compiles them
|
|
with `-fsanitize=fuzzer` via the Rust compiler's LLVM backend, and runs
|
|
the resulting binary. It also manages corpora, artifacts, and coverage
|
|
reports.
|
|
|
|
**Integration pattern for fold:**
|
|
|
|
fold already references cargo-fuzz in `src/cli/fuzz_prep_runner.cpp:462`
|
|
(RF-8: "when running in Rust mode, generate cargo-fuzz-style harnesses").
|
|
The integration plan:
|
|
|
|
```
|
|
fold scan --mode rust → Rust findings with Z3 witnesses
|
|
↓
|
|
fold fuzz-prep --mode rust → emits:
|
|
├─ fuzz/fuzz_targets/target_fn.rs (cargo-fuzz target)
|
|
├─ fuzz/corpus/target_fn/ (Z3-derived seeds)
|
|
└─ fuzz/dictionaries/target_fn.dict (libFuzzer dict)
|
|
↓
|
|
fold fuzz-run --mode rust → cargo +nightly fuzz run target_fn
|
|
↓
|
|
ingest crashes → ConcreteWitness promotion
|
|
```
|
|
|
|
The key difference from C++ fuzz-prep: Rust harnesses compile via `cargo
|
|
fuzz`, not direct `clang++`. The harness generator needs to emit Rust
|
|
source (not C), with `arbitrary::Arbitrary` derives for structured input
|
|
generation. The runner invokes `cargo +nightly fuzz run` instead of
|
|
`clang++ -fsanitize=fuzzer`.
|
|
|
|
**Relevance to fold:** High for Rust validation. This is the Rust-side
|
|
equivalent of fold's existing C++ fuzz-prep→fuzz-run pipeline. The
|
|
infrastructure is already planned (RF-8). Implementation requires:
|
|
(1) a Rust harness emitter, (2) `cargo fuzz` project scaffolding, and
|
|
(3) runner invocation via `cargo` instead of direct `clang++`.
|
|
|
|
---
|
|
|
|
## Binary analysis frameworks
|
|
|
|
### rev.ng
|
|
|
|
| Dimension | Detail |
|
|
|-----------|--------|
|
|
| **Approach** | Binary lifting + decompilation + symbolic execution |
|
|
| **IR level** | QEMU TCG → LLVM IR (via rev.ng's own lifter) |
|
|
| **Languages** | Binary (x86-64, ARM64, MIPS) → lifted LLVM IR |
|
|
| **FP rate** | Depends on analysis. Lifting introduces approximation; decompilation is best-effort. |
|
|
| **Maturity** | Active development. Commercial offering (rev.ng S.r.l.) with open-source components. LLVM 19 support as of 2025. |
|
|
| **License** | GPL-2.0 (open-source core) + proprietary (commercial extensions) |
|
|
| **Key capability** | Lift binaries to LLVM IR, then apply LLVM-based analysis (including libFuzzer fuzzing via dlopen harnesses). |
|
|
|
|
**How it works:**
|
|
|
|
rev.ng lifts machine code to LLVM IR through a multi-stage pipeline:
|
|
(1) disassemble and recover functions, (2) lift to QEMU TCG (Tiny Code
|
|
Generator), (3) translate TCG to rev.ng's intermediate representation,
|
|
and (4) lower to LLVM IR. The resulting LLVM IR can then be analyzed with
|
|
any LLVM-based tool (optimizers, static analyzers, fuzzers). rev.ng also
|
|
includes a decompiler that produces C-like output from the lifted IR.
|
|
|
|
**Integration pattern for fold:**
|
|
|
|
rev.ng is referenced in `docs/internal/binary-fuzz-corpus.md` for the
|
|
dlopen harness pattern. Two integration modes:
|
|
|
|
**Mode A — Lift-then-fuzz (binary→LLVM IR→libFuzzer):**
|
|
|
|
```
|
|
Mach-O / ELF binary → rev.ng lift → LLVM IR (.bc)
|
|
↓
|
|
fold binary-prep → function list (from exported symbols)
|
|
↓
|
|
emit dlopen harness (C source, calls dlsym → target function)
|
|
↓
|
|
clang++ harness.c lifted_module.bc -fsanitize=fuzzer,address → harness.fuzz
|
|
↓
|
|
libFuzzer + ASan → crash artifacts → fold ConcreteWitness
|
|
```
|
|
|
|
This is a substantial capability upgrade: it allows fold's full
|
|
libFuzzer+ASan pipeline to run on binaries without source code.
|
|
The lifted LLVM IR preserves function boundaries and basic-block
|
|
structure, so libFuzzer's coverage instrumentation works.
|
|
|
|
**Mode B — Lift-then-analyze (binary→LLVM IR→fold detectors):**
|
|
|
|
```
|
|
Binary → rev.ng lift → LLVM IR
|
|
↓
|
|
rev.ng decompile → C-like output
|
|
↓
|
|
fold scan --compile-db ... → Z3-powered detectors on lifted code
|
|
```
|
|
|
|
This mode is speculative — lifted LLVM IR is not the same as
|
|
source-level Clang AST output, and fold's detectors expect
|
|
source-level constructs (function declarations, types, CFG
|
|
from Clang). However, for simple functions (no inlining,
|
|
no optimization artifacts), the lifted→decompiled path could
|
|
enable fold's Z3 detectors on binary-only targets.
|
|
|
|
**Relevance to fold:** Medium. rev.ng's lift → LLVM IR pipeline is
|
|
the cleanest path for applying source-level analysis techniques to
|
|
binaries. However, the GPL-2.0 license and commercial split create
|
|
the same friction as KLEE. fold's binary path today uses r2 for
|
|
heuristic extraction — rev.ng would upgrade that to symbolic-quality
|
|
analysis, but at significant integration cost.
|
|
|
|
---
|
|
|
|
## Integration pattern catalog
|
|
|
|
Summary of integration patterns relevant to fold's architecture.
|
|
|
|
### Pattern 1: Subprocess + NDJSON (already shipped)
|
|
|
|
Used by: fold-rust (today), fold-swift (planned), fold's own fuzz orchestrator.
|
|
|
|
```
|
|
fold binary → posix_spawnp("tool", [args...]) → NDJSON stdout → fold parser → findings/summaries
|
|
```
|
|
|
|
**Where it works:** When the tool is a standalone binary with a stable output format.
|
|
**Where it doesn't:** When the tool requires an in-process API (KLEE, Haybale).
|
|
|
|
### Pattern 2: Cargo/Rust crate dependency (planned)
|
|
|
|
Used by: fold-concolic (M31 Phase 3 planned), fold-rust.
|
|
|
|
```
|
|
tools/fold-concolic/Cargo.toml:
|
|
[dependencies]
|
|
libafl = "..."
|
|
haybale = "..." (if chosen for Rust symex)
|
|
|
|
fold binary → fork+exec(fold-concolic) → stdin/argv → findings
|
|
```
|
|
|
|
**Where it works:** When the tool is a Rust library and fold can add a Rust crate.
|
|
**Where it doesn't:** When the tool is C/C++ only (KLEE, SWAN).
|
|
|
|
### Pattern 3: LLVM pass plugin (not yet adopted)
|
|
|
|
Used by: symcc-rt (C++ concolic), rev.ng (binary lifting).
|
|
|
|
```
|
|
fold scan --concolic → clang++ -fpass-plugin=fold_concolic.so → instrumented binary
|
|
```
|
|
|
|
**Where it works:** When the tool is an LLVM pass and fold controls the compiler invocation.
|
|
**Where it doesn't:** When every LLVM release requires pass rewrites (the symcc lesson).
|
|
|
|
### Pattern 4: Harness generation + external runner (shipped)
|
|
|
|
Used by: fold fuzz-prep, fold emit-kani-proof (proposed).
|
|
|
|
```
|
|
fold fuzz-prep → emits harness.{c,rs} + seeds + dict → external runner compiles + runs
|
|
```
|
|
|
|
**Where it works:** When the analysis tool takes a harness/entry point as input.
|
|
**Where it doesn't:** When fold needs runtime feedback during analysis (needs Pattern 1 or 2).
|
|
|
|
### Pattern 5: Detector catalog import (not runtime integration)
|
|
|
|
Used by: Rudra (patterns → fold-rust detectors), Clippy (lint catalog).
|
|
|
|
```
|
|
External tool's detector catalog → re-implement as fold detector.
|
|
```
|
|
|
|
**Where it works:** When the tool is a research prototype whose detectors are the valuable artifact.
|
|
**Where it doesn't:** When the tool's analysis engine is the valuable artifact (KLEE, Kani, Miri).
|
|
|
|
---
|
|
|
|
## Architecture expansion recommendations
|
|
|
|
Based on the landscape analysis, fold's architecture expansion should follow
|
|
these priorities:
|
|
|
|
### Tier 0 — Ship what's already scoped (current sprint)
|
|
|
|
| Item | Tool | Pattern | Status |
|
|
|------|------|---------|--------|
|
|
| Rust MIR validation via Miri | Miri | Harness gen + external runner | Scoped as RF-8 in `fuzz_prep_runner.cpp:462` |
|
|
| Swift SIL scanning | SWAN | Subprocess + NDJSON | Scoped as Task 73 (tools/fold-swift/) |
|
|
| Concolic execution | LibAFL+symcc-rt | Rust crate dependency | Scoped as M31 Phase 3 |
|
|
|
|
### Tier 1 — High-impact, low-risk additions (next 2-3 sprints)
|
|
|
|
1. **Rust Kani bridge.** `fold emit-kani-proof` command that generates
|
|
Kani harnesses from fold-rust findings. Kani verifies (proves or
|
|
counterexamples) the flagged functions. ~200 lines of Rust in
|
|
`tools/fold-rust/`, leveraging fold-rust's existing `rustc_driver`
|
|
infrastructure.
|
|
|
|
2. **Haybale spike for Rust symex.** Evaluate whether Haybale can
|
|
load and symbolically execute LLVM bitcode from fold-rust targets.
|
|
If viable, Haybale could be the Rust-side counterpart to the C++
|
|
side's Z3 encoder — providing `Proved` confidence (not just
|
|
`Heuristic`) for Rust findings without crossing the language
|
|
barrier.
|
|
|
|
3. **AFL++ QEMU mode for binary fuzz.** Extend `fold binary-fuzz-prep`
|
|
(currently documented in `docs/internal/binary-fuzz-corpus.md` but
|
|
unimplemented) to emit dlopen harnesses and run AFL++ QEMU mode
|
|
against Mach-O binaries. This closes the binary fuzz gap without
|
|
requiring source code or LLVM bitcode.
|
|
|
|
### Tier 2 — Medium-impact, medium-risk (next 6 months)
|
|
|
|
4. **Rudra detector catalog import.** Add Rudra's top-10 highest-yield
|
|
patterns (send/sync, unsafe API, panic safety) to fold-rust as HIR
|
|
visitors. Target: fold-rust finds at least 50% of what Rudra found
|
|
(56 advisories out of 112) via HIR pattern matching alone.
|
|
|
|
5. **MIRAI-style MIR visitor for fold-rust.** Add a MIR visitor layer to
|
|
`tools/fold-rust/` that performs interval analysis and taint tracking
|
|
on monomorphized MIR. This would upgrade fold-rust from "mostly HIR
|
|
pattern matching" to "has path-sensitive analysis" — closing the
|
|
precision gap between fold-rust and fold's C++ encoder.
|
|
|
|
6. **rev.ng lift-then-fuzz spike.** Evaluate the "lift binary to LLVM IR
|
|
then fuzz with libFuzzer" pipeline on a small Mach-O fixture. If the
|
|
lifted IR is stable enough for coverage-guided fuzzing, this unlocks
|
|
fold's full Z3+libFuzzer pipeline for binary-only targets.
|
|
|
|
### Tier 3 — Strategic, high-risk (long-term)
|
|
|
|
7. **KLEE integration.** If fold's license posture changes to accommodate
|
|
GPL-2.0 (or if KLEE adopts GPL-3.0 or a later-compatible exception),
|
|
KLEE would provide exhaustive bounded path coverage from entry points,
|
|
complementing fold's per-sink SAT approach. This is the verification
|
|
tier fold currently lacks for C++.
|
|
|
|
8. **SWAN taint integration for fold-swift.** Beyond the SIL pattern
|
|
matching covered in Task 73, integrate SWAN's taint analysis framework
|
|
as a subprocess to add `taint-track` findings to the Swift frontend.
|
|
|
|
### Decision rules by language target
|
|
|
|
| Language | Scan-time analysis | Validation/confirmation | Concolic/symex |
|
|
|----------|-------------------|------------------------|----------------|
|
|
| **C++** | Z3 encoder (shipped) | libFuzzer+ASan (shipped) | LibAFL+symcc-rt (planned) |
|
|
| **Rust** | HIR visitors (shipped MVP) | Miri + cargo-fuzz (planned) | Haybale spike (Tier 1) |
|
|
| **Swift** | SIL visitors (Task 73) | ASan via fuzzing (future) | SWAN taint (Tier 3) |
|
|
| **Binary** | r2 heuristics (shipped) | AFL++ QEMU (Tier 1) | rev.ng lift-then-analyze (Tier 2) |
|
|
|
|
### What NOT to pursue
|
|
|
|
- **Prusti, Creusot, Verus (Rust deductive verifiers).** These are
|
|
verification tools requiring user-written specifications in separation
|
|
logic or Rust-specific assertion languages. fold's value is bottom-up
|
|
scanning without user annotations. They are complementary, not
|
|
integrable.
|
|
- **SymCC pass port (Option A from M31 Phase 3).** The maintenance
|
|
burden of owning an LLVM pass across releases was explicitly rejected
|
|
in `docs/internal/m31-phase3-concolic.md`. LibAFL+symcc-rt (Option B)
|
|
is the chosen path.
|
|
- **CodeQL for fold's own detectors.** CodeQL is a CPG query engine,
|
|
not a symbolic execution tool. fold already has superior arithmetic
|
|
reasoning via Z3. CodeQL's strengths (interprocedural dataflow,
|
|
declarative queries) overlap with fold's taint-track detector and
|
|
are not a differentiator.
|
|
|
|
---
|
|
|
|
## References
|
|
|
|
### Tool homepages
|
|
|
|
| Tool | URL |
|
|
|------|-----|
|
|
| KLEE | https://klee.github.io/ |
|
|
| Kani | https://model-checking.github.io/kani/ |
|
|
| Rudra | https://github.com/sslab-gatech/Rudra |
|
|
| MIRAI | https://github.com/facebookexperimental/MIRAI |
|
|
| Miri | https://github.com/rust-lang/miri |
|
|
| Haybale | https://github.com/trailofbits/haybale |
|
|
| AFL++ | https://github.com/AFLplusplus/AFLplusplus |
|
|
| LibAFL | https://github.com/AFLplusplus/LibAFL |
|
|
| libFuzzer | https://llvm.org/docs/LibFuzzer.html |
|
|
| cargo-fuzz | https://github.com/rust-fuzz/cargo-fuzz |
|
|
| rev.ng | https://rev.ng/ |
|
|
| SWAN | https://github.com/S2-group/swan |
|
|
|
|
### fold internal docs
|
|
|
|
| Doc | What it covers |
|
|
|-----|---------------|
|
|
| `docs/internal/binary-fuzz-corpus.md` | Mach-O binary → ABI inference → dlopen harness pattern |
|
|
| `docs/internal/swift-sil-z3-corpus.md` | Swift SIL operations, Z3 API reference, detector map |
|
|
| `docs/internal/rust-frontend.md` | fold-rust architecture, subprocess wire format, known limits |
|
|
| `docs/internal/m31-phase3-concolic.md` | LibAFL+symcc-rt concolic execution plan |
|
|
| `docs/internal/library-expansion-matrix.md` | Z3 and Clang feature adoption scorecard |
|
|
| `docs/positioning.md` | fold vs peer tools, confidence tiers, when to choose fold |
|
|
| `docs/research/prior-art.md` | Key papers grounding fold's design |
|
|
| `docs/research/frontier.md` | Optimization and validation tiers (T0-T4 + future) |
|
|
|
|
### Key papers
|
|
|
|
| Paper | Relevance to this landscape |
|
|
|-------|---------------------------|
|
|
| Cadar et al. (2008) *KLEE: Unassisted and Automatic Generation of High-Coverage Tests* | KLEE architecture and design rationale |
|
|
| Poeplau & Francillon (2020) *SymQEMU: Compilation-based symbolic execution for binaries* | Binary-level symbolic execution; alternative to rev.ng |
|
|
| Fioraldi et al. (2020) *AFL++: Combining Incremental Steps of Fuzzing Research* | AFL++ architecture; LibAFL design |
|
|
| Jung et al. (2020) *Stacked Borrows* | Miri's pointer provenance model |
|
|
| Astrauskas et al. (2019) *Leveraging Rust Types for Modular Specification and Verification* | Prusti architecture; why deductive verifiers are outside fold's scope |
|
|
| Vanhatalo et al. (2021) *Automatic Rust Unsafe Code Analysis* (Rudra) | Rudra's detector design and ecosystem impact |
|
|
| Toman & Grossman (2021) *Concrat: Symbolic Execution for Rust* | Rust-specific symbolic execution; relevant to Haybale evaluation |
|