diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2024-04-15 14:55:02 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2024-04-16 14:20:36 +0000 |
| commit | 68911a35911bfdeb62bef87d9e844b1c19f86580 (patch) | |
| tree | a13c0f84b1e1c19cfb2fee8defdfb1cd566ecfba /syz-manager | |
| parent | 4cd91fc0b5007710bf0f38de6319ce24c31a52e5 (diff) | |
syz-manager, syz-fuzzer: send exec encoded programs to fuzzer
Don't send text program to the fuzzer,
instead send exec encoding directly.
It's more compact now and does not need complex deserialization.
Diffstat (limited to 'syz-manager')
| -rw-r--r-- | syz-manager/rpc.go | 49 | ||||
| -rw-r--r-- | syz-manager/stats.go | 1 |
2 files changed, 34 insertions, 16 deletions
diff --git a/syz-manager/rpc.go b/syz-manager/rpc.go index 4a260738e..94f902085 100644 --- a/syz-manager/rpc.go +++ b/syz-manager/rpc.go @@ -45,6 +45,7 @@ type RPCServer struct { statExecs *stats.Val statExecRetries *stats.Val + statExecBufferTooSmall *stats.Val statVMRestarts *stats.Val statExchangeCalls *stats.Val statExchangeProgs *stats.Val @@ -95,6 +96,8 @@ func startRPCServer(mgr *Manager) (*RPCServer, error) { statExecRetries: stats.Create("exec retries", "Number of times a test program was restarted because the first run failed", stats.Rate{}, stats.Graph("executor")), + statExecBufferTooSmall: stats.Create("buffer too small", + "Program serialization overflowed exec buffer", stats.NoGraph), statVMRestarts: stats.Create("vm restarts", "Total number of VM starts", stats.Rate{}, stats.NoGraph), statExchangeCalls: stats.Create("exchange calls", "Number of RPC Exchange calls", @@ -243,20 +246,32 @@ func (serv *RPCServer) ExchangeInfo(a *rpctype.ExchangeInfoRequest, r *rpctype.E return nil } - fuzzer := serv.mgr.getFuzzer() - if fuzzer == nil { + fuzzerObj := serv.mgr.getFuzzer() + if fuzzerObj == nil { // ExchangeInfo calls follow MachineCheck, so the fuzzer must have been initialized. panic("exchange info call with nil fuzzer") } + appendRequest := func(inp *fuzzer.Request) { + if req, ok := runner.newRequest(inp); ok { + r.Requests = append(r.Requests, req) + } else { + // It's bad if we systematically fail to serialize programs, + // but so far we don't have a better handling than counting this. + // This error is observed a lot on the seeded syz_mount_image calls. + serv.statExecBufferTooSmall.Add(1) + fuzzerObj.Done(inp, &fuzzer.Result{Stop: true}) + } + } + // Try to collect some of the postponed requests. if serv.mu.TryLock() { - for i := len(serv.rescuedInputs) - 1; i >= 0 && a.NeedProgs > 0; i-- { - inp := serv.rescuedInputs[i] - serv.rescuedInputs[i] = nil - serv.rescuedInputs = serv.rescuedInputs[:i] - r.Requests = append(r.Requests, runner.newRequest(inp)) - a.NeedProgs-- + for len(serv.rescuedInputs) != 0 && len(r.Requests) < a.NeedProgs { + last := len(serv.rescuedInputs) - 1 + inp := serv.rescuedInputs[last] + serv.rescuedInputs[last] = nil + serv.rescuedInputs = serv.rescuedInputs[:last] + appendRequest(inp) } serv.mu.Unlock() } @@ -264,13 +279,12 @@ func (serv *RPCServer) ExchangeInfo(a *rpctype.ExchangeInfoRequest, r *rpctype.E // First query new inputs and only then post results. // It should foster a more even distribution of executions // across all VMs. - for i := 0; i < a.NeedProgs; i++ { - inp := fuzzer.NextInput() - r.Requests = append(r.Requests, runner.newRequest(inp)) + for len(r.Requests) < a.NeedProgs { + appendRequest(fuzzerObj.NextInput()) } for _, result := range a.Results { - runner.doneRequest(result, fuzzer, serv.cfg.Cover) + runner.doneRequest(result, fuzzerObj, serv.cfg.Cover) } stats.Import(a.StatsDelta) @@ -407,7 +421,12 @@ func (runner *Runner) doneRequest(resp rpctype.ExecutionResult, fuzzerObj *fuzze fuzzerObj.Done(req.req, &fuzzer.Result{Info: info}) } -func (runner *Runner) newRequest(req *fuzzer.Request) rpctype.ExecutionRequest { +func (runner *Runner) newRequest(req *fuzzer.Request) (rpctype.ExecutionRequest, bool) { + progData, err := req.Prog.SerializeForExec() + if err != nil { + return rpctype.ExecutionRequest{}, false + } + var signalFilter signal.Signal if req.SignalFilter != nil { newRawSignal := runner.instModules.Decanonicalize(req.SignalFilter.ToRaw()) @@ -425,13 +444,13 @@ func (runner *Runner) newRequest(req *fuzzer.Request) rpctype.ExecutionRequest { runner.mu.Unlock() return rpctype.ExecutionRequest{ ID: id, - ProgData: req.Prog.Serialize(), + ProgData: progData, NeedCover: req.NeedCover, NeedSignal: req.NeedSignal, SignalFilter: signalFilter, SignalFilterCall: req.SignalFilterCall, NeedHints: req.NeedHints, - } + }, true } func (runner *Runner) logProgram(procID int, p *prog.Prog) { diff --git a/syz-manager/stats.go b/syz-manager/stats.go index 53373cf7e..a0719bc45 100644 --- a/syz-manager/stats.go +++ b/syz-manager/stats.go @@ -78,7 +78,6 @@ func (mgr *Manager) initStats() { // Stats imported from the fuzzer (names must match the the fuzzer names). stats.Create("executor restarts", "Number of times executor process was restarted", stats.Rate{}, stats.Graph("executor")) - stats.Create("buffer too small", "Program serialization overflowed exec buffer", stats.NoGraph) stats.Create("no exec requests", "Number of times fuzzer was stalled with no exec requests", stats.Rate{}) stats.Create("no exec duration", "Total duration fuzzer was stalled with no exec requests (ns/sec)", stats.Rate{}) } |
