Grammar fuzzing: fresh workers without throwing away the campaign

Started by Anoncto@anoncto••0 views•1 replies
A
Anoncto@anoncto
VIP
16
0
#1

Coverage can tell you that two operations ran. It does not necessarily tell you that the output of one reached the other. That is a fairly important distinction when the bug needs a particular chain of operations.

Project Zero's grammar-fuzzing writeup gives a useful libxslt example: the result of document() must reach generate-id(). Separate calls can cover the same code without creating that dataflow. Even combining useful fragments might add no new coverage, so a coverage-only admission rule need not keep the combination.

The corpus can get stuck without coverage stopping

Local mutations also preserve large chunks of their parents. A growing corpus can therefore contain plenty of new coverage and plenty of inherited similarity.

The interesting workaround in the writeup is not “restart the target more often.” It changes the lifetime of the worker's corpus, while retaining the campaign's accumulated history on a server:

  1. Start a worker with an empty corpus and run independently for T.
  2. Sync missing coverage and corresponding samples in both directions with the persistent server.
  3. Run for another T with the combined corpus.
  4. Sync again, replace the worker and its local corpus, then repeat.

Each generation gets an independent exploration phase before inheriting earlier discoveries. The server survives; the whole campaign is not reset.

What would make the comparison useful?

The author reports four one-week, single-machine experiments on older libxslt/libxml2 snapshots: two uninterrupted baselines and renewal with T=600 and T=3600 seconds. The renewal runs found more unique crashes, and found crashes sooner, than the uninterrupted baselines; one hour worked best for that target.

That is an interesting result, not a universal timer. Unique crashes are not necessarily distinct root causes, and those runs do not establish the best interval for another target.

My takeaway: keep the campaign's discoveries, but give new workers time to explore without inheriting the same starting point.

To compare the strategies, I would measure independently triaged bug yield under a fixed machine-hour budget, keeping the target build, grammar, harness and crash-deduplication rule constant. Record initial-sync timing and server history too: a nominally fresh worker that immediately imports everything is a different experiment.

For a grammar-based campaign, what evidence would make you trade continuous corpus sharing for independent worker generations with delayed sync—especially if edge coverage kept growing in both?

0

Join the conversation!