Skip to content

workloads/lnd: map coverage counters directly onto AFL's map - #261

Merged
morehouse merged 3 commits into
lnfuzz:masterfrom
erickcestari:lnd-direct-coverage-map
Sep 28, 2026
Merged

morehouse merged 3 commits into
lnfuzz:masterfrom
erickcestari:lnd-direct-coverage-map

Conversation

@erickcestari

@erickcestari erickcestari commented Sep 18, 2026 •

Copy link
Copy Markdown
Member

Remap Go's libfuzzer counter section onto the AFL shared memory instead of copying it on every sync. Startup coverage no longer pollutes every map, and crashing or timed-out inputs now report coverage.

The trigger/ack pipes stay as a liveness handshake: try_wait still sees a just-crashed LND as running.

I didn't yet run an evaluation to see the coverage increasing, but this should align the coverage report with the others implementation. Where the startup coverage don't pollute every map, since each input will be started from a zeroed map.

@erickcestari

Copy link
Copy Markdown
Member Author

Target: lnd

Median Coverage Over Time

image

Distribution Comparisons

Final Edge Coverage Area Under Curve (Speed)
image image

Comment thread smite-scenarios/src/targets/lnd.rs Outdated
Comment thread workloads/lnd/sancov.go
Comment thread workloads/lnd/sancov.go Outdated
Comment thread workloads/lnd/sancov.go Outdated
Comment thread workloads/lnd/sancov.go Outdated
Comment thread workloads/lnd/sancov.go
Remap Go's libfuzzer counter section onto the AFL shared memory instead
of copying it on every sync. Startup coverage no longer pollutes every
map, and crashing or timed-out inputs now report coverage.

The trigger/ack pipes stay as a liveness handshake: try_wait still sees
a just-crashed LND as running.
try_wait only sees a crashed multithreaded process once it is reapable,
after the kernel has closed its sockets, so a scenario can see the
connection drop while the target still looks alive. Also check
PF_EXITING, which the kernel sets before closing any file. Teardown keeps
waiting for the reap through has_exited().
Replaces the trigger/ack pipe handshake. The handler reports Go fatal
errors before LND's sockets close, and reports now carry the Go
traceback. ALLOW_HANDLER_OVERRIDE lets Go keep its own signal handlers,
which it needs to recover nil dereferences.

@morehouse morehouse left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great!

I tested both crash detection and coverage feedback as follows:

  1. Patched LND to crash when decoding a message that begins with "SMTE", with a separate branch for each letter.
  2. Fuzzed encrypted_bytes for ~1 hour, after which the crash was reported

The crash log:

caught signal: 6

panic: smite: injected crash

goroutine ... [running]:
panic(...)
	/usr/local/go/src/runtime/panic.go:879
github.com/lightningnetwork/lnd/peer.(*Brontide).readNextMessage.func1(...)
	/lnd/peer/brontide.go:1940 github.com/lightningnetwork/lnd/peer.(*Brontide).readNextMessage.(*Read).Submit.func2(...)
...

The lineage of the crashing input:

Queue entry Found at Starts with
id:000000 seed AAAA
id:000004 exec 94 SAAA
id:000559 9 min SMMM
id:000961 60 min SMTM
crash 60.1 min SMTE

Each input in the lineage adds a single letter and triggers a new branch, so it appears the coverage feedback is working correctly.

@morehouse
morehouse merged commit 61bdad0 into lnfuzz:master Sep 28, 2026
5 checks passed
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