From 2be2288ee256f3b84a7de15b82894097a08fd939 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Sun, 18 Feb 2018 12:09:37 +0100 Subject: [PATCH] syz-fuzzer: don't break syscalls during minimization If the original call was successful, keep it successful during minimization. Successful calls are much more valuable. --- syz-fuzzer/proc.go | 25 ++++++++++++++++++------- syz-fuzzer/workqueue.go | 9 +++++---- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/syz-fuzzer/proc.go b/syz-fuzzer/proc.go index 9f7eb6973248..605febeb8d4b 100644 --- a/syz-fuzzer/proc.go +++ b/syz-fuzzer/proc.go @@ -103,7 +103,7 @@ func (proc *Proc) triageInput(item *WorkTriage) { panic("should not be called when coverage is disabled") } - newSignal := proc.fuzzer.corpusSignalDiff(item.signal) + newSignal := proc.fuzzer.corpusSignalDiff(item.info.Signal) if len(newSignal) == 0 { return } @@ -151,6 +151,11 @@ func (proc *Proc) triageInput(item *WorkTriage) { continue // The call was not executed. } inf := info[call1] + if item.info.Errno == 0 && inf.Errno != 0 { + // Don't minimize calls from successful to unsuccessful. + // Successful calls are much more valuable. + return false + } signal := cover.Canonicalize(inf.Signal) if len(cover.Intersection(newSignal, signal)) == len(newSignal) { return true @@ -167,11 +172,11 @@ func (proc *Proc) triageInput(item *WorkTriage) { proc.fuzzer.sendInputToManager(RpcInput{ Call: call.CallName, Prog: data, - Signal: []uint32(cover.Canonicalize(item.signal)), + Signal: []uint32(cover.Canonicalize(item.info.Signal)), Cover: []uint32(inputCover), }) - proc.fuzzer.addInputToCorpus(item.p, item.signal, sig) + proc.fuzzer.addInputToCorpus(item.p, item.info.Signal, sig) if item.flags&ProgSmashed == 0 { proc.fuzzer.workQueue.enqueue(&WorkSmash{item.p, item.call}) @@ -228,11 +233,17 @@ func (proc *Proc) executeHintSeed(p *prog.Prog, call int) { func (proc *Proc) execute(execOpts *ipc.ExecOpts, p *prog.Prog, flags ProgTypes, stat Stat) []ipc.CallInfo { info := proc.executeRaw(execOpts, p, stat) for _, callIndex := range proc.fuzzer.checkNewSignal(info) { + info := info[callIndex] + // info.Signal points to the output shmem region, detach it before queueing. + info.Signal = append([]uint32{}, info.Signal...) + // None of the caller use Cover, so just nil it instead of detaching. + // Note: triage input uses executeRaw to get coverage. + info.Cover = nil proc.fuzzer.workQueue.enqueue(&WorkTriage{ - p: p.Clone(), - call: callIndex, - signal: append([]uint32{}, info[callIndex].Signal...), - flags: flags, + p: p.Clone(), + call: callIndex, + info: info, + flags: flags, }) } return info diff --git a/syz-fuzzer/workqueue.go b/syz-fuzzer/workqueue.go index 80905af261df..62648336ca50 100644 --- a/syz-fuzzer/workqueue.go +++ b/syz-fuzzer/workqueue.go @@ -6,6 +6,7 @@ package main import ( "sync" + "github.com/google/syzkaller/pkg/ipc" "github.com/google/syzkaller/prog" ) @@ -38,10 +39,10 @@ const ( // During triage we understand if these programs in fact give new coverage, // and if yes, minimize them and add to corpus. type WorkTriage struct { - p *prog.Prog - call int - signal []uint32 - flags ProgTypes + p *prog.Prog + call int + info ipc.CallInfo + flags ProgTypes } // WorkCandidate are programs from hub.