From 9232148686b36aed88151c1bf82b1a1294d76f37 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Mon, 29 Apr 2024 07:55:44 +0200 Subject: syz-fuzzer: pass bug frames in connect result Move bug frames from check result to connect result. This allows to create gate and start executing programs in the syz-fuzzer earlier (before check finished). This will be required for moving syscall/feature checks to the host. --- pkg/rpctype/rpctype.go | 8 ++++---- syz-fuzzer/fuzzer.go | 40 ++++++++++++++++++++++------------------ syz-manager/manager.go | 11 ++++++++--- syz-manager/rpc.go | 11 +++++++---- 4 files changed, 41 insertions(+), 29 deletions(-) diff --git a/pkg/rpctype/rpctype.go b/pkg/rpctype/rpctype.go index fa728a494..d9119d24e 100644 --- a/pkg/rpctype/rpctype.go +++ b/pkg/rpctype/rpctype.go @@ -76,8 +76,10 @@ type ConnectArgs struct { } type ConnectRes struct { - EnabledCalls []int - AllSandboxes bool + EnabledCalls []int + MemoryLeakFrames []string + DataRaceFrames []string + AllSandboxes bool // This is forwarded from CheckArgs, if checking was already done. Features *host.Features // Fuzzer reads these files inside of the VM and returns contents in CheckArgs.Files. @@ -96,8 +98,6 @@ type CheckArgs struct { } type CheckRes struct { - MemoryLeakFrames []string - DataRaceFrames []string CoverFilterBitmap []byte } diff --git a/syz-fuzzer/fuzzer.go b/syz-fuzzer/fuzzer.go index 6068f6b62..cdce3b21f 100644 --- a/syz-fuzzer/fuzzer.go +++ b/syz-fuzzer/fuzzer.go @@ -167,6 +167,28 @@ func main() { } checkReq = new(rpctype.CheckArgs) } + + for _, feat := range r.Features.Supported() { + log.Logf(0, "%v: %v", feat.Name, feat.Reason) + } + + inputsCount := *flagProcs * 2 + fuzzerTool := &FuzzerTool{ + name: *flagName, + manager: manager, + timeouts: timeouts, + + requests: make(chan rpctype.ExecutionRequest, inputsCount), + results: make(chan executionResult, inputsCount), + } + gateCb := fuzzerTool.useBugFrames(r.Features, r.MemoryLeakFrames, r.DataRaceFrames) + fuzzerTool.gate = ipc.NewGate(gateSize, gateCb) + + log.Logf(0, "starting %v executor processes", *flagProcs) + for pid := 0; pid < *flagProcs; pid++ { + startProc(fuzzerTool, pid, config, *flagResetAccState) + } + checkReq.Name = *flagName checkReq.Files = host.ReadFiles(r.ReadFiles) checkReq.Globs = make(map[string][]string) @@ -184,25 +206,11 @@ func main() { if checkReq.Error != "" { log.SyzFatalf("%v", checkReq.Error) } - for _, feat := range r.Features.Supported() { - log.Logf(0, "%v: %v", feat.Name, feat.Reason) - } if *flagRunTest { runTest(target, manager, *flagName, executor) return } - inputsCount := *flagProcs * 2 - fuzzerTool := &FuzzerTool{ - name: *flagName, - manager: manager, - timeouts: timeouts, - - requests: make(chan rpctype.ExecutionRequest, inputsCount), - results: make(chan executionResult, inputsCount), - } - gateCb := fuzzerTool.useBugFrames(r.Features, checkRes.MemoryLeakFrames, checkRes.DataRaceFrames) - fuzzerTool.gate = ipc.NewGate(gateSize, gateCb) if checkRes.CoverFilterBitmap != nil { if err := osutil.WriteFile("syz-cover-bitmap", checkRes.CoverFilterBitmap); err != nil { log.SyzFatalf("failed to write syz-cover-bitmap: %v", err) @@ -210,10 +218,6 @@ func main() { } // Query enough inputs at the beginning. fuzzerTool.exchangeDataCall(inputsCount, nil, 0) - log.Logf(0, "starting %v executor processes", *flagProcs) - for pid := 0; pid < *flagProcs; pid++ { - startProc(fuzzerTool, pid, config, *flagResetAccState) - } go fuzzerTool.exchangeDataWorker() fuzzerTool.exchangeDataWorker() } diff --git a/syz-manager/manager.go b/syz-manager/manager.go index 6fe51d6e3..b25d938da 100644 --- a/syz-manager/manager.go +++ b/syz-manager/manager.go @@ -1330,10 +1330,9 @@ func (mgr *Manager) collectSyscallInfo() map[string]*corpus.CallCov { return calls } -func (mgr *Manager) fuzzerConnect() (BugFrames, map[uint32]uint32, signal.Signal) { +func (mgr *Manager) currentBugFrames() BugFrames { mgr.mu.Lock() defer mgr.mu.Unlock() - frames := BugFrames{ memoryLeaks: make([]string, 0, len(mgr.memoryLeakFrames)), dataRaces: make([]string, 0, len(mgr.dataRaceFrames)), @@ -1344,8 +1343,14 @@ func (mgr *Manager) fuzzerConnect() (BugFrames, map[uint32]uint32, signal.Signal for frame := range mgr.dataRaceFrames { frames.dataRaces = append(frames.dataRaces, frame) } + return frames +} + +func (mgr *Manager) fuzzerConnect() (map[uint32]uint32, signal.Signal) { + mgr.mu.Lock() + defer mgr.mu.Unlock() maxSignal := mgr.fuzzer.Load().Cover.CopyMaxSignal() - return frames, mgr.execCoverFilter, maxSignal + return mgr.execCoverFilter, maxSignal } func (mgr *Manager) machineChecked(features *host.Features, globFiles map[string][]string, diff --git a/syz-manager/rpc.go b/syz-manager/rpc.go index 96283ee20..5c22bdc0e 100644 --- a/syz-manager/rpc.go +++ b/syz-manager/rpc.go @@ -86,7 +86,8 @@ type BugFrames struct { // RPCManagerView restricts interface between RPCServer and Manager. type RPCManagerView interface { - fuzzerConnect() (BugFrames, map[uint32]uint32, signal.Signal) + currentBugFrames() BugFrames + fuzzerConnect() (map[uint32]uint32, signal.Signal) machineChecked(features *host.Features, globFiles map[string][]string, enabledSyscalls map[*prog.Syscall]bool, modules []host.KernelModule) getFuzzer() *fuzzer.Fuzzer @@ -133,6 +134,10 @@ func (serv *RPCServer) Connect(a *rpctype.ConnectArgs, r *rpctype.ConnectRes) er checkRevisions(a, serv.cfg.Target) serv.statVMRestarts.Add(1) + bugFrames := serv.mgr.currentBugFrames() + r.MemoryLeakFrames = bugFrames.memoryLeaks + r.DataRaceFrames = bugFrames.dataRaces + serv.mu.Lock() defer serv.mu.Unlock() r.EnabledCalls = serv.cfg.Syscalls @@ -185,7 +190,7 @@ func (serv *RPCServer) Check(a *rpctype.CheckArgs, r *rpctype.CheckRes) error { serv.checkDone = true } - bugFrames, execCoverFilter, maxSignal := serv.mgr.fuzzerConnect() + execCoverFilter, maxSignal := serv.mgr.fuzzerConnect() runner := serv.findRunner(a.Name) if runner == nil { @@ -202,8 +207,6 @@ func (serv *RPCServer) Check(a *rpctype.CheckArgs, r *rpctype.CheckRes) error { runner.instModules = serv.canonicalModules.NewInstance(modules) runner.newMaxSignal = maxSignal - r.MemoryLeakFrames = bugFrames.memoryLeaks - r.DataRaceFrames = bugFrames.dataRaces instCoverFilter := runner.instModules.DecanonicalizeFilter(execCoverFilter) r.CoverFilterBitmap = createCoverageBitmap(serv.cfg.SysTarget, instCoverFilter) return nil -- cgit mrf-deployment