Skip to main content

Crate global_state_detector

Crate global_state_detector 

Source
Expand description

Detect persistent writable state between fuzzer iterations.

Rust bindings for the global-state-detector C library. Operates on writable, non-executable ELF PT_LOAD segments (.data / .bss) of the main binary and every loaded shared object, filtering out libc / ld-linux / libpthread / libstdc++ / vDSO noise.

§Usage

Call init once after any one-time target initialization is done. Then, on each fuzzer iteration, rebaseline just before invoking the target and check just after. That pattern attributes drift to the target rather than to the fuzzer’s own bookkeeping between callbacks.

§Required linker flags for the final binary

Cargo does not propagate rustc-link-arg from rlib dependencies, so consumers must arrange for the linker to receive -rdynamic and -Wl,-z,now themselves. The simplest way is a .cargo/config.toml in the consuming project (or its fuzz/ subdirectory):

[target.'cfg(target_os = "linux")']
rustflags = ["-C", "link-arg=-rdynamic", "-C", "link-arg=-Wl,-z,now"]

Without -rdynamic, symbol names in the main executable are not resolvable via dladdr and reports show ?+0x... instead of real symbols. Without -Wl,-z,now, lazy PLT/GOT binding produces noise on the first iteration.

§Rust-specific caveats

  • static and static mut live in .data/.bss — fully covered.
  • AtomicU*, Mutex<T> (the lock word), RwLock — covered.
  • OnceCell, OnceLock, LazyLock, lazy_static! — only the pointer / discriminant in .bss is visible. The actual heap- allocated payload is NOT tracked. You will see “this static was first-used in this iteration” but not what value it took.
  • thread_local! lives in TLS, not .data/.bss — not tracked here. TLS is per-thread anyway, less of a fuzzing concern.
  • Symbols come out Rust-mangled (_ZN8... / _R...). Pipe stderr through rustfilt to demangle: ./fuzzer 2>&1 | rustfilt (cargo install rustfilt)

§Thread safety

The underlying C implementation is not thread-safe. Use it from a single-threaded harness, or add external synchronization.

Functions§

check
Diff current memory against the last snapshot.
init
Snapshot all writable PT_LOAD segments of the main binary and every currently loaded shared object.
rebaseline
Force a full re-snapshot without reporting any diffs.