diff --git a/syz-verifier/verifier.go b/syz-verifier/verifier.go index d57a9f6c847c..29db18a460ae 100644 --- a/syz-verifier/verifier.go +++ b/syz-verifier/verifier.go @@ -7,11 +7,13 @@ import ( "context" "fmt" "net" + "path/filepath" "strings" "sync" "sync/atomic" "time" + "github.com/google/syzkaller/pkg/db" "github.com/google/syzkaller/pkg/flatrpc" "github.com/google/syzkaller/pkg/fuzzer" "github.com/google/syzkaller/pkg/fuzzer/queue" @@ -42,7 +44,7 @@ type Verifier struct { firstConnect atomic.Int64 // unix time, or 0 if not connected. // Corpus management - load once at startup from the first config's workdir. - programs []*prog.Prog + programs chan *prog.Prog } // Kernel represents a single kernel configuration in the verification process. @@ -101,7 +103,7 @@ func (vrf *Verifier) RunVerifierFuzzer(ctx context.Context) error { } } eg.Go(func() error { - vrf.preloadCorpus() + vrf.preloadCorpus(ctx) return nil }) eg.Go(func() error { @@ -111,19 +113,38 @@ func (vrf *Verifier) RunVerifierFuzzer(ctx context.Context) error { return eg.Wait() } -func (vrf *Verifier) preloadCorpus() { +func (vrf *Verifier) preloadCorpus(ctx context.Context) { log.Logf(0, "loading corpus.db") - info, err := manager.LoadSeeds(vrf.cfg, false) + dbPath := filepath.Join(vrf.cfg.Workdir, "corpus.db") + corpusDB, err := db.Open(dbPath, true) if err != nil { - log.Fatalf("failed to load corpus: %v", err) - } - vrf.programs = make([]*prog.Prog, len(info.Candidates)) - for i, candidate := range info.Candidates { - vrf.programs[i] = candidate.Prog + log.Fatalf("failed to open corpus.db: %v", err) } - log.Logf(0, "loaded %d corpus programs for verification", len(vrf.programs)) + vrf.programs = make(chan *prog.Prog, len(corpusDB.Records)) + loadedCount := 0 + for key, rec := range corpusDB.Records { + p, err := manager.ParseSeed(vrf.target, rec.Val) + if err != nil { + log.Logf(1, "skipping program %x: %v", key, err) + continue + } + + select { + case <-ctx.Done(): + log.Logf(0, "corpus loading canceled by context") + corpusDB.DiscardData() + close(vrf.programs) + return + case vrf.programs <- p: + loadedCount++ + } + } + // Drop the records from memory + corpusDB.DiscardData() + close(vrf.programs) + log.Logf(0, "loaded %d corpus programs for verification", loadedCount) } // Loop starts the main verifier execution loop. @@ -168,11 +189,9 @@ func (vrf *Verifier) verifierLoop(ctx context.Context) { statSyscalls := stat.New("syscalls", "Number of enabled syscalls", stat.Simple, stat.NoGraph, stat.Link("/syscalls")) statSyscalls.Add(len(totalEnabledSyscalls)) - // Log enabled syscalls. - log.Logf(1, "starting to compare %d programs from given corpus", len(vrf.programs)) - // The main verifier loop: iterate through corpus programs and compare across kernels. - for progIdx, prog := range vrf.programs { + progIdx := 0 + for prog := range vrf.programs { // Check context. select { case <-ctx.Done(): @@ -180,7 +199,7 @@ func (vrf *Verifier) verifierLoop(ctx context.Context) { default: } - log.Logf(1, "comparing program %d/%d", progIdx+1, len(vrf.programs)) + log.Logf(1, "comparing program %d", progIdx+1) // Create requests for all kernels. requests, responses, wg := vrf.createRequests(prog) @@ -194,6 +213,8 @@ func (vrf *Verifier) verifierLoop(ctx context.Context) { // Compare execution results. vrf.compareResults(prog, responses) + + progIdx++ } }