mirror of
https://github.com/reactos/syzkaller.git
synced 2025-02-20 03:21:26 +00:00

We reset disabled syscalls before checking them. As the result no diagnostics printed. Reset them after checking.
176 lines
4.6 KiB
Go
176 lines
4.6 KiB
Go
// Copyright 2018 syzkaller project authors. All rights reserved.
|
|
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
|
|
|
|
package main
|
|
|
|
import (
|
|
"net"
|
|
"sync"
|
|
|
|
"github.com/google/syzkaller/pkg/cover"
|
|
"github.com/google/syzkaller/pkg/log"
|
|
"github.com/google/syzkaller/pkg/rpctype"
|
|
"github.com/google/syzkaller/pkg/signal"
|
|
"github.com/google/syzkaller/prog"
|
|
"github.com/google/syzkaller/sys"
|
|
)
|
|
|
|
type RPCServer struct {
|
|
mgr RPCManagerView
|
|
target *prog.Target
|
|
enabledSyscalls []int
|
|
stats *Stats
|
|
batchSize int
|
|
|
|
mu sync.Mutex
|
|
fuzzers map[string]*Fuzzer
|
|
checkResult *rpctype.CheckArgs
|
|
maxSignal signal.Signal
|
|
corpusSignal signal.Signal
|
|
corpusCover cover.Cover
|
|
}
|
|
|
|
type Fuzzer struct {
|
|
name string
|
|
inputs []rpctype.RPCInput
|
|
newMaxSignal signal.Signal
|
|
}
|
|
|
|
// RPCManagerView restricts interface between RPCServer and Manager.
|
|
type RPCManagerView interface {
|
|
fuzzerConnect() ([]rpctype.RPCInput, [][]byte)
|
|
machineChecked(result *rpctype.CheckArgs)
|
|
newInput(inp rpctype.RPCInput, sign signal.Signal)
|
|
candidateBatch(size int) []rpctype.RPCCandidate
|
|
}
|
|
|
|
func startRPCServer(mgr *Manager) (int, error) {
|
|
serv := &RPCServer{
|
|
mgr: mgr,
|
|
target: mgr.target,
|
|
enabledSyscalls: mgr.enabledSyscalls,
|
|
stats: mgr.stats,
|
|
fuzzers: make(map[string]*Fuzzer),
|
|
}
|
|
serv.batchSize = 5
|
|
if serv.batchSize < mgr.cfg.Procs {
|
|
serv.batchSize = mgr.cfg.Procs
|
|
}
|
|
s, err := rpctype.NewRPCServer(mgr.cfg.RPC, "Manager", serv)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
log.Logf(0, "serving rpc on tcp://%v", s.Addr())
|
|
port := s.Addr().(*net.TCPAddr).Port
|
|
go s.Serve()
|
|
return port, nil
|
|
}
|
|
|
|
func (serv *RPCServer) Connect(a *rpctype.ConnectArgs, r *rpctype.ConnectRes) error {
|
|
log.Logf(1, "fuzzer %v connected", a.Name)
|
|
serv.stats.vmRestarts.inc()
|
|
|
|
corpus, memoryLeakFrames := serv.mgr.fuzzerConnect()
|
|
|
|
serv.mu.Lock()
|
|
defer serv.mu.Unlock()
|
|
|
|
serv.fuzzers[a.Name] = &Fuzzer{
|
|
name: a.Name,
|
|
inputs: corpus,
|
|
newMaxSignal: serv.maxSignal.Copy(),
|
|
}
|
|
r.MemoryLeakFrames = memoryLeakFrames
|
|
r.EnabledCalls = serv.enabledSyscalls
|
|
r.CheckResult = serv.checkResult
|
|
r.GitRevision = sys.GitRevision
|
|
r.TargetRevision = serv.target.Revision
|
|
return nil
|
|
}
|
|
|
|
func (serv *RPCServer) Check(a *rpctype.CheckArgs, r *int) error {
|
|
serv.mu.Lock()
|
|
defer serv.mu.Unlock()
|
|
|
|
if serv.checkResult != nil {
|
|
return nil
|
|
}
|
|
serv.mgr.machineChecked(a)
|
|
a.DisabledCalls = nil
|
|
serv.checkResult = a
|
|
return nil
|
|
}
|
|
|
|
func (serv *RPCServer) NewInput(a *rpctype.NewInputArgs, r *int) error {
|
|
inputSignal := a.Signal.Deserialize()
|
|
log.Logf(4, "new input from %v for syscall %v (signal=%v, cover=%v)",
|
|
a.Name, a.Call, inputSignal.Len(), len(a.Cover))
|
|
if _, err := serv.target.Deserialize(a.RPCInput.Prog, prog.NonStrict); err != nil {
|
|
// This should not happen, but we see such cases episodically, reason unknown.
|
|
log.Logf(0, "failed to deserialize program from fuzzer: %v\n%s", err, a.RPCInput.Prog)
|
|
return nil
|
|
}
|
|
serv.mu.Lock()
|
|
defer serv.mu.Unlock()
|
|
|
|
if serv.corpusSignal.Diff(inputSignal).Empty() {
|
|
return nil
|
|
}
|
|
serv.mgr.newInput(a.RPCInput, inputSignal)
|
|
|
|
serv.stats.newInputs.inc()
|
|
serv.corpusSignal.Merge(inputSignal)
|
|
serv.stats.corpusSignal.set(serv.corpusSignal.Len())
|
|
serv.corpusCover.Merge(a.Cover)
|
|
serv.stats.corpusCover.set(len(serv.corpusCover))
|
|
|
|
a.RPCInput.Cover = nil // Don't send coverage back to all fuzzers.
|
|
for _, f := range serv.fuzzers {
|
|
if f.name == a.Name {
|
|
continue
|
|
}
|
|
f.inputs = append(f.inputs, a.RPCInput)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (serv *RPCServer) Poll(a *rpctype.PollArgs, r *rpctype.PollRes) error {
|
|
serv.stats.mergeNamed(a.Stats)
|
|
|
|
serv.mu.Lock()
|
|
defer serv.mu.Unlock()
|
|
|
|
f := serv.fuzzers[a.Name]
|
|
if f == nil {
|
|
log.Fatalf("fuzzer %v is not connected", a.Name)
|
|
}
|
|
newMaxSignal := serv.maxSignal.Diff(a.MaxSignal.Deserialize())
|
|
if !newMaxSignal.Empty() {
|
|
serv.maxSignal.Merge(newMaxSignal)
|
|
for _, f1 := range serv.fuzzers {
|
|
if f1 == f {
|
|
continue
|
|
}
|
|
f1.newMaxSignal.Merge(newMaxSignal)
|
|
}
|
|
}
|
|
r.MaxSignal = f.newMaxSignal.Split(500).Serialize()
|
|
if a.NeedCandidates {
|
|
r.Candidates = serv.mgr.candidateBatch(serv.batchSize)
|
|
}
|
|
if len(r.Candidates) == 0 {
|
|
for i := 0; i < serv.batchSize && len(f.inputs) > 0; i++ {
|
|
last := len(f.inputs) - 1
|
|
r.NewInputs = append(r.NewInputs, f.inputs[last])
|
|
f.inputs[last] = rpctype.RPCInput{}
|
|
f.inputs = f.inputs[:last]
|
|
}
|
|
if len(f.inputs) == 0 {
|
|
f.inputs = nil
|
|
}
|
|
}
|
|
log.Logf(4, "poll from %v: candidates=%v inputs=%v maxsignal=%v",
|
|
a.Name, len(r.Candidates), len(r.NewInputs), len(r.MaxSignal.Elems))
|
|
return nil
|
|
}
|