skip known case if the file is actually coming from us

Assume we have one main node and N secondary nodes in a parallel
fuzzing campaign. Every time the main node found a new case, the case
will be synced to all secondary nodes. Later when the main node sync,
the main node need to run the file again to see if the file is
interesting because they are "new" cases on the secondary nodes.

In other words, for one new case, the main node has to run the redundent
test N times. This is wasteful and slowed down the progress of main
node.

The wasteful issue on secondary nodes is acceptable because we can run
more secondary nodes to mitigate the inefficiency. OTOH, increasing the
number of secondary nodes slow down the main node further.
This commit is contained in:
Kuang-che Wu
2025-05-16 20:19:56 +08:00
parent 59c2198532
commit 7c27fc7cfe

View File

@ -699,6 +699,35 @@ abort_calibration:
} }
bool is_known_case(afl_state_t *afl, u8 *name, void *mem, u32 len) {
int sync_id_pos;
u32 id, src_id;
if (sscanf(name, "id:%06u,sync:%n%*[^,],src:%06u", &id, &sync_id_pos,
&src_id) != 2)
return false;
if (strncmp(name + sync_id_pos, afl->sync_id, strlen(afl->sync_id)) != 0)
return false;
if (name[sync_id_pos + strlen(afl->sync_id)] != ',') return false;
if (src_id < 0 || src_id >= afl->queued_items) return false;
struct queue_entry *q = afl->queue_buf[src_id];
if (q->len != len) return false;
if (q->testcase_buf) return memcmp(q->testcase_buf, mem, len) == 0;
int fd = open((char *)q->fname, O_RDONLY);
if (fd < 0) return false;
u8 *buf = malloc(len);
ck_read(fd, buf, len, q->fname);
close(fd);
bool result = (memcmp(buf, mem, len) == 0);
free(buf);
return result;
}
/* Grab interesting test cases from other fuzzers. */ /* Grab interesting test cases from other fuzzers. */
void sync_fuzzers(afl_state_t *afl) { void sync_fuzzers(afl_state_t *afl) {
@ -896,27 +925,31 @@ void sync_fuzzers(afl_state_t *afl) {
if (mem == MAP_FAILED) { PFATAL("Unable to mmap '%s'", path); } if (mem == MAP_FAILED) { PFATAL("Unable to mmap '%s'", path); }
/* See what happens. We rely on save_if_interesting() to catch major if (!is_known_case(afl, namelist[o]->d_name, mem, st.st_size)) {
errors and save the test case. */
u32 new_len = write_to_testcase(afl, (void **)&mem, st.st_size, 1); /* See what happens. We rely on save_if_interesting() to catch major
errors and save the test case. */
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); u32 new_len = write_to_testcase(afl, (void **)&mem, st.st_size, 1);
if (afl->stop_soon) { fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
munmap(mem, st.st_size); if (afl->stop_soon) {
close(fd);
goto close_sync; munmap(mem, st.st_size);
close(fd);
goto close_sync;
}
afl->syncing_party = sd_ent->d_name;
afl->queued_imported += save_if_interesting(afl, mem, new_len, fault);
show_stats(afl);
afl->syncing_party = 0;
} }
afl->syncing_party = sd_ent->d_name;
afl->queued_imported += save_if_interesting(afl, mem, new_len, fault);
show_stats(afl);
afl->syncing_party = 0;
munmap(mem, st.st_size); munmap(mem, st.st_size);
} }