Skip to content

Commit d979a81

Browse files
committed
all: do comparison substitution for extra coverage
Collect comparison arguments for extra coverage. For that, we now need to start remote coverage collection for every forked program. Substitute the arguments into all calls that have remote_cover set.
1 parent 34889ee commit d979a81

File tree

3 files changed

+55
-52
lines changed

3 files changed

+55
-52
lines changed

executor/executor.cc

Lines changed: 28 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -508,10 +508,6 @@ int main(int argc, char** argv)
508508
cover_open(&extra_cov, true);
509509
cover_mmap(&extra_cov);
510510
cover_protect(&extra_cov);
511-
if (flag_extra_coverage) {
512-
// Don't enable comps because we don't use them in the fuzzer yet.
513-
cover_enable(&extra_cov, false, true);
514-
}
515511
char sep = '/';
516512
#if GOOS_windows
517513
sep = '\\';
@@ -753,7 +749,7 @@ void execute_one()
753749
if (!flag_threaded)
754750
cover_enable(&threads[0].cov, flag_comparisons, false);
755751
if (flag_extra_coverage)
756-
cover_reset(&extra_cov);
752+
cover_enable(&extra_cov, flag_comparisons, true);
757753
}
758754

759755
int call_index = 0;
@@ -1110,20 +1106,11 @@ void copyout_call_results(thread_t* th)
11101106
}
11111107
}
11121108

1113-
void write_call_output(thread_t* th, bool finished)
1109+
void write_call_shmem_output(int call_index, int call_num, uint32 reserrno, uint32 call_flags, cover_t* cov)
11141110
{
1115-
uint32 reserrno = ENOSYS;
1116-
const bool blocked = finished && th != last_scheduled;
1117-
uint32 call_flags = call_flag_executed | (blocked ? call_flag_blocked : 0);
1118-
if (finished) {
1119-
reserrno = th->res != -1 ? 0 : th->reserrno;
1120-
call_flags |= call_flag_finished |
1121-
(th->fault_injected ? call_flag_fault_injected : 0);
1122-
}
1123-
#if SYZ_EXECUTOR_USES_SHMEM
11241111
write_output(kOutMagic);
1125-
write_output(th->call_index);
1126-
write_output(th->call_num);
1112+
write_output(call_index);
1113+
write_output(call_num);
11271114
write_output(reserrno);
11281115
write_output(call_flags);
11291116
uint32* signal_count_pos = write_output(0); // filled in later
@@ -1132,15 +1119,15 @@ void write_call_output(thread_t* th, bool finished)
11321119

11331120
if (flag_comparisons) {
11341121
// Collect only the comparisons
1135-
uint32 ncomps = th->cov.size;
1136-
kcov_comparison_t* start = (kcov_comparison_t*)(th->cov.data + sizeof(uint64));
1122+
uint32 ncomps = cov->size;
1123+
kcov_comparison_t* start = (kcov_comparison_t*)(cov->data + sizeof(uint64));
11371124
kcov_comparison_t* end = start + ncomps;
1138-
if ((char*)end > th->cov.data_end)
1125+
if ((char*)end > cov->data_end)
11391126
failmsg("too many comparisons", "ncomps=%u", ncomps);
1140-
cover_unprotect(&th->cov);
1127+
cover_unprotect(cov);
11411128
std::sort(start, end);
11421129
ncomps = std::unique(start, end) - start;
1143-
cover_protect(&th->cov);
1130+
cover_protect(cov);
11441131
uint32 comps_size = 0;
11451132
for (uint32 i = 0; i < ncomps; ++i) {
11461133
if (start[i].ignore())
@@ -1152,15 +1139,29 @@ void write_call_output(thread_t* th, bool finished)
11521139
*comps_count_pos = comps_size;
11531140
} else if (flag_collect_signal || flag_collect_cover) {
11541141
if (is_kernel_64_bit)
1155-
write_coverage_signal<uint64>(&th->cov, signal_count_pos, cover_count_pos);
1142+
write_coverage_signal<uint64>(cov, signal_count_pos, cover_count_pos);
11561143
else
1157-
write_coverage_signal<uint32>(&th->cov, signal_count_pos, cover_count_pos);
1144+
write_coverage_signal<uint32>(cov, signal_count_pos, cover_count_pos);
11581145
}
11591146
debug_verbose("out #%u: index=%u num=%u errno=%d finished=%d blocked=%d sig=%u cover=%u comps=%u\n",
1160-
completed, th->call_index, th->call_num, reserrno, finished, blocked,
1147+
completed, call_index, call_num, reserrno, finished, blocked,
11611148
*signal_count_pos, *cover_count_pos, *comps_count_pos);
11621149
completed++;
11631150
write_completed(completed);
1151+
}
1152+
1153+
void write_call_output(thread_t* th, bool finished)
1154+
{
1155+
uint32 reserrno = ENOSYS;
1156+
const bool blocked = finished && th != last_scheduled;
1157+
uint32 call_flags = call_flag_executed | (blocked ? call_flag_blocked : 0);
1158+
if (finished) {
1159+
reserrno = th->res != -1 ? 0 : th->reserrno;
1160+
call_flags |= call_flag_finished |
1161+
(th->fault_injected ? call_flag_fault_injected : 0);
1162+
}
1163+
#if SYZ_EXECUTOR_USES_SHMEM
1164+
write_call_shmem_output(th->call_index, th->call_num, reserrno, call_flags, &th->cov);
11641165
#else
11651166
call_reply reply;
11661167
reply.header.magic = kOutMagic;
@@ -1184,27 +1185,13 @@ void write_call_output(thread_t* th, bool finished)
11841185
void write_extra_output()
11851186
{
11861187
#if SYZ_EXECUTOR_USES_SHMEM
1187-
if (!cover_collection_required() || !flag_extra_coverage || flag_comparisons)
1188+
if (!cover_collection_required() || !flag_extra_coverage)
11881189
return;
11891190
cover_collect(&extra_cov);
11901191
if (!extra_cov.size)
11911192
return;
1192-
write_output(kOutMagic);
1193-
write_output(-1); // call index
1194-
write_output(-1); // call num
1195-
write_output(999); // errno
1196-
write_output(0); // call flags
1197-
uint32* signal_count_pos = write_output(0); // filled in later
1198-
uint32* cover_count_pos = write_output(0); // filled in later
1199-
write_output(0); // comps_count_pos
1200-
if (is_kernel_64_bit)
1201-
write_coverage_signal<uint64>(&extra_cov, signal_count_pos, cover_count_pos);
1202-
else
1203-
write_coverage_signal<uint32>(&extra_cov, signal_count_pos, cover_count_pos);
1193+
write_call_shmem_output(-1, -1, 999, 0, &extra_cov);
12041194
cover_reset(&extra_cov);
1205-
debug_verbose("extra: sig=%u cover=%u\n", *signal_count_pos, *cover_count_pos);
1206-
completed++;
1207-
write_completed(completed);
12081195
#endif // if SYZ_EXECUTOR_USES_SHMEM
12091196
}
12101197

pkg/fuzzer/job.go

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ type smashJob struct {
259259

260260
func (job *smashJob) run(fuzzer *Fuzzer) {
261261
fuzzer.Logf(2, "smashing the program %s (call=%d):", job.p, job.call)
262-
if fuzzer.Config.Comparisons && job.call >= 0 {
262+
if fuzzer.Config.Comparisons {
263263
fuzzer.startJob(fuzzer.statJobsHints, &hintsJob{
264264
p: job.p.Clone(),
265265
call: job.call,
@@ -360,8 +360,15 @@ func (job *hintsJob) run(fuzzer *Fuzzer) {
360360
if result.Stop() || result.Info == nil {
361361
return
362362
}
363+
call := result.Info.Extra
364+
if job.call >= 0 {
365+
call = result.Info.Calls[job.call]
366+
}
367+
if call == nil {
368+
return
369+
}
363370
got := make(prog.CompMap)
364-
for _, cmp := range result.Info.Calls[job.call].Comps {
371+
for _, cmp := range call.Comps {
365372
got.AddComp(cmp.Op1, cmp.Op2)
366373
}
367374
if len(got) == 0 {
@@ -377,13 +384,19 @@ func (job *hintsJob) run(fuzzer *Fuzzer) {
377384
// Then mutate the initial program for every match between
378385
// a syscall argument and a comparison operand.
379386
// Execute each of such mutants to check if it gives new coverage.
380-
p.MutateWithHints(job.call, comps,
381-
func(p *prog.Prog) bool {
382-
result := fuzzer.execute(fuzzer.smashQueue, &queue.Request{
383-
Prog: p,
384-
ExecOpts: setFlags(flatrpc.ExecFlagCollectSignal),
385-
Stat: fuzzer.statExecHint,
386-
})
387-
return !result.Stop()
388-
})
387+
388+
for i := 0; i < len(p.Calls); i++ {
389+
// For .extra coverage, substitute arguments to all calls with remote_cover.
390+
if i == job.call || job.call < 0 && job.p.Calls[i].Meta.Attrs.RemoteCover {
391+
p.MutateWithHints(i, comps,
392+
func(p *prog.Prog) bool {
393+
result := fuzzer.execute(fuzzer.smashQueue, &queue.Request{
394+
Prog: p,
395+
ExecOpts: setFlags(flatrpc.ExecFlagCollectSignal),
396+
Stat: fuzzer.statExecHint,
397+
})
398+
return !result.Stop()
399+
})
400+
}
401+
}
389402
}

pkg/ipc/ipc.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,9 @@ func convertExtra(extraParts []flatrpc.CallInfo, dedupCover bool) *flatrpc.CallI
403403
extra.Signal[i] = uint64(s)
404404
i++
405405
}
406+
for _, part := range extraParts {
407+
extra.Comps = append(extra.Comps, part.Comps...)
408+
}
406409
return &extra
407410
}
408411

0 commit comments

Comments
 (0)