From ebd71c054bab8fad556745259f1d7974ed60095d Mon Sep 17 00:00:00 2001 From: Aleksandr Nogikh Date: Wed, 7 Aug 2024 15:09:53 +0200 Subject: syz-manager: switch snapshots to dispatcher.Pool It lets us get bug reproductions out of box. --- pkg/mgrconfig/load.go | 3 --- syz-manager/manager.go | 50 ++++++++++++++++++++++++------------------------- syz-manager/snapshot.go | 33 ++++++++++++++++---------------- 3 files changed, 40 insertions(+), 46 deletions(-) diff --git a/pkg/mgrconfig/load.go b/pkg/mgrconfig/load.go index 9120dd236..aa22b3ea8 100644 --- a/pkg/mgrconfig/load.go +++ b/pkg/mgrconfig/load.go @@ -150,9 +150,6 @@ func Complete(cfg *Config) error { ); err != nil { return err } - if cfg.Snapshot && cfg.Reproduce { - return fmt.Errorf("reproduction is not (yet) supported in snapshot mode") - } cfg.Workdir = osutil.Abs(cfg.Workdir) if cfg.WorkdirTemplate != "" { cfg.WorkdirTemplate = osutil.Abs(cfg.WorkdirTemplate) diff --git a/syz-manager/manager.go b/syz-manager/manager.go index ec4fc5dd4..2efacc4c8 100644 --- a/syz-manager/manager.go +++ b/syz-manager/manager.go @@ -86,7 +86,6 @@ type Manager struct { corpusPreload chan []fuzzer.Candidate firstConnect atomic.Int64 // unix time, or 0 if not connected crashTypes map[string]bool - loopStop func() enabledFeatures flatrpc.Feature checkDone atomic.Bool fresh bool @@ -317,17 +316,7 @@ func RunManager(mode Mode, cfg *mgrconfig.Config) { ctx := vm.ShutdownCtx() go mgr.processFuzzingResults(ctx) go mgr.reproMgr.Loop(ctx) - - loopCtx, cancel := context.WithCancel(ctx) - mgr.loopStop = cancel - mgr.pool.Loop(loopCtx) - - if cfg.Snapshot { - log.Logf(0, "starting VMs for snapshot mode") - mgr.serv.Close() - mgr.serv = nil - mgr.snapshotLoop() - } + mgr.pool.Loop(ctx) } // Exit successfully in special operation modes. @@ -686,11 +675,23 @@ func loadProg(target *prog.Target, data []byte) (*prog.Prog, error) { } func (mgr *Manager) fuzzerInstance(ctx context.Context, inst *vm.Instance, updInfo dispatcher.UpdateInfo) { + mgr.mu.Lock() + serv := mgr.serv + mgr.mu.Unlock() + if serv == nil { + // We're in the process of switching off the RPCServer. + return + } injectExec := make(chan bool, 10) - mgr.serv.CreateInstance(inst.Index(), injectExec, updInfo) - - rep, vmInfo, err := mgr.runInstanceInner(ctx, inst, injectExec) - lastExec, machineInfo := mgr.serv.ShutdownInstance(inst.Index(), rep != nil) + serv.CreateInstance(inst.Index(), injectExec, updInfo) + + rep, vmInfo, err := mgr.runInstanceInner(ctx, inst, injectExec, vm.EarlyFinishCb(func() { + // Depending on the crash type and kernel config, fuzzing may continue + // running for several seconds even after kernel has printed a crash report. + // This litters the log and we want to prevent it. + serv.StopFuzzing(inst.Index()) + })) + lastExec, machineInfo := serv.ShutdownInstance(inst.Index(), rep != nil) if rep != nil { rpcserver.PrependExecuting(rep, lastExec) if len(vmInfo) != 0 { @@ -709,8 +710,8 @@ func (mgr *Manager) fuzzerInstance(ctx context.Context, inst *vm.Instance, updIn } } -func (mgr *Manager) runInstanceInner(ctx context.Context, inst *vm.Instance, - injectExec <-chan bool) (*report.Report, []byte, error) { +func (mgr *Manager) runInstanceInner(ctx context.Context, inst *vm.Instance, injectExec <-chan bool, + finishCb vm.EarlyFinishCb) (*report.Report, []byte, error) { fwdAddr, err := inst.Forward(mgr.serv.Port) if err != nil { return nil, nil, fmt.Errorf("failed to setup port forwarding: %w", err) @@ -736,12 +737,7 @@ func (mgr *Manager) runInstanceInner(ctx context.Context, inst *vm.Instance, cmd := fmt.Sprintf("%v runner %v %v %v", executorBin, inst.Index(), host, port) _, rep, err := inst.Run(mgr.cfg.Timeouts.VMRunningTime, mgr.reporter, cmd, vm.ExitTimeout, vm.StopContext(ctx), vm.InjectExecuting(injectExec), - vm.EarlyFinishCb(func() { - // Depending on the crash type and kernel config, fuzzing may continue - // running for several seconds even after kernel has printed a crash report. - // This litters the log and we want to prevent it. - mgr.serv.StopFuzzing(inst.Index()) - }), + finishCb, ) if err != nil { return nil, nil, fmt.Errorf("failed to run fuzzer: %w", err) @@ -1335,9 +1331,11 @@ func (mgr *Manager) MachineChecked(features flatrpc.Feature, enabledSyscalls map } source := queue.DefaultOpts(fuzzerObj, opts) if mgr.cfg.Snapshot { - log.Logf(0, "stopping VMs for snapshot mode") + log.Logf(0, "restarting VMs for snapshot mode") mgr.source = source - mgr.loopStop() + mgr.pool.SetDefault(mgr.snapshotInstance) + mgr.serv.Close() + mgr.serv = nil return queue.Callback(func() *queue.Request { return nil }) diff --git a/syz-manager/snapshot.go b/syz-manager/snapshot.go index 484ae8ff4..b76c58583 100644 --- a/syz-manager/snapshot.go +++ b/syz-manager/snapshot.go @@ -5,6 +5,7 @@ package main import ( "bytes" + "context" "errors" "fmt" "time" @@ -14,27 +15,24 @@ import ( "github.com/google/syzkaller/pkg/fuzzer/queue" "github.com/google/syzkaller/pkg/log" "github.com/google/syzkaller/vm" + "github.com/google/syzkaller/vm/dispatcher" ) -func (mgr *Manager) snapshotLoop() { - queue.StatNumFuzzing.Add(mgr.vmPool.Count()) - for index := 0; index < mgr.vmPool.Count(); index++ { - index := index - go func() { - for { - log.Error(mgr.snapshotVM(index)) - } - }() - } - select {} -} +func (mgr *Manager) snapshotInstance(ctx context.Context, inst *vm.Instance, updInfo dispatcher.UpdateInfo) { + queue.StatNumFuzzing.Add(1) + defer queue.StatNumFuzzing.Add(-1) + + updInfo(func(info *dispatcher.Info) { + info.Status = "snapshot fuzzing" + }) -func (mgr *Manager) snapshotVM(index int) error { - inst, err := mgr.vmPool.Create(index) + err := mgr.snapshotLoop(ctx, inst) if err != nil { - return err + log.Error(err) } - defer inst.Close() +} + +func (mgr *Manager) snapshotLoop(ctx context.Context, inst *vm.Instance) error { executor, err := inst.Copy(mgr.cfg.ExecutorBin) if err != nil { return err @@ -48,7 +46,7 @@ func (mgr *Manager) snapshotVM(index int) error { builder := flatbuffers.NewBuilder(0) var envFlags flatrpc.ExecEnv - for first := true; ; first = false { + for first := true; ctx.Err() == nil; first = false { queue.StatExecs.Add(1) req := mgr.source.Next() if first { @@ -81,6 +79,7 @@ func (mgr *Manager) snapshotVM(index int) error { req.Done(res) } + return nil } func (mgr *Manager) snapshotSetup(inst *vm.Instance, builder *flatbuffers.Builder, env flatrpc.ExecEnv) error { -- cgit mrf-deployment