Skip to content

Add e9patch binary rewriting for runtime function call tracing#1

Open
overlorde wants to merge 2 commits intosysec-uic:mainfrom
overlorde:add-binary-rewriting-log-feature
Open

Add e9patch binary rewriting for runtime function call tracing#1
overlorde wants to merge 2 commits intosysec-uic:mainfrom
overlorde:add-binary-rewriting-log-feature

Conversation

@overlorde
Copy link
Copy Markdown

Summary

  • Adds e9patch-based binary rewriting to record ordered function call sequences at runtime
  • Integrates the recorded trace data into the existing path tracing infrastructure (CurrentExecutionPath, ComputePathDistance(), DumpCurrentPath())
  • Currently only tested on libxml2 using the ARVO harness (bug 42470339)

Background

The existing counter-based path recorder in FuzzerTracePC.cpp records each focus function once per execution with call_id=1, losing temporal ordering and call counts. This adds an alternative trace source using e9patch binary rewriting that captures the actual ordered call sequence with real per-input call counts.

Changes

New files:

  • FuzzerE9Trace.h/cpp — shared memory buffer between the e9patch hook and libFuzzer
  • e9patch_experiments/ — e9patch hook source, toy test target, build/run scripts, documentation
  • docker-e9/ — Dockerfile and scripts for building and running the libxml2 pipeline

Modified files:

  • FuzzerTracePC.cpp — added CollectE9Trace(), InitE9SymbolTable(), GetFunctionName() (dladdr fallback for environments without sanitizer symbolization)
  • FuzzerTracePC.h — new method declarations
  • FuzzerLoop.cpp — calls e9_trace_reset() before execution and CollectE9Trace() after

How to run

# libxml2 end-to-end (requires Docker)
./docker-e9/run_full_pipeline.sh

# Toy target (requires e9patch installed via setup.sh)
cd e9patch_experiments && ./setup.sh && ./run_integrated.sh

What is tested

  • e9patch hook correctly records ordered function call sequences on a toy target and libxml2
  • Hook filters calls inside the trampoline — only focus function calls are recorded (no buffer noise)
  • CollectE9Trace() populates CurrentExecutionPath with correct function names and per-input call counts
  • JSON trace output via DumpCurrentPath() produces valid traces with input hex, ASCII, and ordered path

What is NOT tested

  • Path-aware fuzzing (-crash_path_file + -path_distance_threshold) — traces are generated and fed into ComputePathDistance() but the effect on fuzzing decisions has not been validated
  • Only tested on libxml2; no other targets
  • Performance impact of patching all call instructions not measured

Build requirements

Target binary must be compiled with:

  • -fno-inline -fno-optimize-sibling-calls — keeps call instructions for e9patch to hook
  • -rdynamic -ldl — exports symbols for dladdr resolution

Known limitations

  • e9tool F.name matching does not fire at runtime; workaround is asm=/call.*/ which patches all call instructions
  • ASan is incompatible with e9patch trampolines; crash detection requires a separate unpatched binary

Replaces the broken counter-based path tracing (which always produced
call_id=1) with real ordered call sequences via e9patch binary rewriting.

The e9patch hook instruments all call instructions at the binary level,
recording target addresses into a shared memory buffer. After each fuzzer
execution, CollectE9Trace() reads the buffer, resolves addresses to
function names via static offsets, and populates CurrentExecutionPath
with real ordered data. This makes ComputePathDistance() and
DumpCurrentPath() now functional.

New files:
- FuzzerE9Trace.h/cpp: shared trace buffer between hook and libFuzzer
- e9patch_experiments/: hook source, toy target, build scripts, docs
- docker-e9/: Dockerfile and scripts for libxml2 end-to-end pipeline

Modified:
- FuzzerTracePC.cpp: added CollectE9Trace(), InitE9SymbolTable(),
  GetFunctionName() with dladdr fallback for symbolization without
  sanitizer runtime
- FuzzerTracePC.h: added new method declarations
- FuzzerLoop.cpp: added e9_trace_reset() before and CollectE9Trace()
  after each execution, InitE9SymbolTable() at startup

Tested end-to-end on libxml2 with ARVO crash PoC (bug 42470339).
@Kenan-Kamel Kenan-Kamel self-requested a review April 2, 2026 19:01
@Kenan-Kamel Kenan-Kamel self-assigned this Apr 2, 2026
@Kenan-Kamel
Copy link
Copy Markdown
Collaborator

Thanks @overlorde, the new PR is received for path-aware fuzz harness re-write, it should be mereged back with the main/master branch soon.

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.

2 participants