mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-23 11:29:46 +00:00
syz-fuzzer: add more checks for disabled syscalls
We are seeing some panics that say that some disabled syscalls somehow get into corpus. I don't see where/how this can happen. Add a check to syz-fuzzer to panic whenever we execute a program with disabled syscall. Hopefull the panic stack will shed some light. Also add a check in manager as the last defence line so that bad programs don't get into the corpus.
This commit is contained in:
parent
fa822db46a
commit
413b991c26
@ -254,7 +254,7 @@ func (target *Target) BuildChoiceTable(corpus []*Prog, enabled map[*Syscall]bool
|
||||
return &ChoiceTable{target, run, enabledCalls}
|
||||
}
|
||||
|
||||
func (ct *ChoiceTable) enabled(call int) bool {
|
||||
func (ct *ChoiceTable) Enabled(call int) bool {
|
||||
return ct.runs[call] != nil
|
||||
}
|
||||
|
||||
@ -262,13 +262,13 @@ func (ct *ChoiceTable) choose(r *rand.Rand, bias int) int {
|
||||
if bias < 0 {
|
||||
bias = ct.calls[r.Intn(len(ct.calls))].ID
|
||||
}
|
||||
if !ct.enabled(bias) {
|
||||
if !ct.Enabled(bias) {
|
||||
panic("bias to disabled syscall")
|
||||
}
|
||||
run := ct.runs[bias]
|
||||
x := r.Intn(run[len(run)-1]) + 1
|
||||
res := sort.SearchInts(run, x)
|
||||
if !ct.enabled(res) {
|
||||
if !ct.Enabled(res) {
|
||||
panic("selected disabled syscall")
|
||||
}
|
||||
return res
|
||||
|
@ -379,7 +379,7 @@ func (r *randGen) createResource(s *state, res *ResourceType, dir Dir) (arg Arg,
|
||||
// TODO: reduce priority of less specialized ctors.
|
||||
var metas []*Syscall
|
||||
for _, meta := range metas0 {
|
||||
if s.ct.enabled(meta.ID) {
|
||||
if s.ct.Enabled(meta.ID) {
|
||||
metas = append(metas, meta)
|
||||
}
|
||||
}
|
||||
|
@ -277,6 +277,11 @@ func (proc *Proc) executeRaw(opts *ipc.ExecOpts, p *prog.Prog, stat Stat) *ipc.P
|
||||
if opts.Flags&ipc.FlagDedupCover == 0 {
|
||||
log.Fatalf("dedup cover is not enabled")
|
||||
}
|
||||
for _, call := range p.Calls {
|
||||
if !proc.fuzzer.choiceTable.Enabled(call.Meta.ID) {
|
||||
panic(fmt.Sprintf("executing disabled syscall %v", call.Meta.Name))
|
||||
}
|
||||
}
|
||||
|
||||
// Limit concurrency window and do leak checking once in a while.
|
||||
ticket := proc.fuzzer.gate.Enter()
|
||||
|
@ -65,9 +65,10 @@ type Manager struct {
|
||||
|
||||
dash *dashapi.Dashboard
|
||||
|
||||
mu sync.Mutex
|
||||
phase int
|
||||
enabledSyscalls []int
|
||||
mu sync.Mutex
|
||||
phase int
|
||||
configEnabledSyscalls []int
|
||||
targetEnabledSyscalls map[*prog.Syscall]bool
|
||||
|
||||
candidates []rpctype.RPCCandidate // untriaged inputs from corpus and hub
|
||||
disabledHashes map[string]struct{}
|
||||
@ -157,27 +158,27 @@ func RunManager(cfg *mgrconfig.Config, target *prog.Target, sysTarget *targets.T
|
||||
}
|
||||
|
||||
mgr := &Manager{
|
||||
cfg: cfg,
|
||||
vmPool: vmPool,
|
||||
target: target,
|
||||
sysTarget: sysTarget,
|
||||
reporter: reporter,
|
||||
crashdir: crashdir,
|
||||
startTime: time.Now(),
|
||||
stats: &Stats{haveHub: cfg.HubClient != ""},
|
||||
crashTypes: make(map[string]bool),
|
||||
enabledSyscalls: syscalls,
|
||||
corpus: make(map[string]rpctype.RPCInput),
|
||||
disabledHashes: make(map[string]struct{}),
|
||||
memoryLeakFrames: make(map[string]bool),
|
||||
dataRaceFrames: make(map[string]bool),
|
||||
fresh: true,
|
||||
vmStop: make(chan bool),
|
||||
hubReproQueue: make(chan *Crash, 10),
|
||||
needMoreRepros: make(chan chan bool),
|
||||
reproRequest: make(chan chan map[string]bool),
|
||||
usedFiles: make(map[string]time.Time),
|
||||
saturatedCalls: make(map[string]bool),
|
||||
cfg: cfg,
|
||||
vmPool: vmPool,
|
||||
target: target,
|
||||
sysTarget: sysTarget,
|
||||
reporter: reporter,
|
||||
crashdir: crashdir,
|
||||
startTime: time.Now(),
|
||||
stats: &Stats{haveHub: cfg.HubClient != ""},
|
||||
crashTypes: make(map[string]bool),
|
||||
configEnabledSyscalls: syscalls,
|
||||
corpus: make(map[string]rpctype.RPCInput),
|
||||
disabledHashes: make(map[string]struct{}),
|
||||
memoryLeakFrames: make(map[string]bool),
|
||||
dataRaceFrames: make(map[string]bool),
|
||||
fresh: true,
|
||||
vmStop: make(chan bool),
|
||||
hubReproQueue: make(chan *Crash, 10),
|
||||
needMoreRepros: make(chan chan bool),
|
||||
reproRequest: make(chan chan map[string]bool),
|
||||
usedFiles: make(map[string]time.Time),
|
||||
saturatedCalls: make(map[string]bool),
|
||||
}
|
||||
|
||||
log.Logf(0, "loading corpus...")
|
||||
@ -469,10 +470,6 @@ func (mgr *Manager) loadCorpus() {
|
||||
fallthrough
|
||||
case currentDBVersion:
|
||||
}
|
||||
syscalls := make(map[int]bool)
|
||||
for _, id := range mgr.checkResult.EnabledCalls[mgr.cfg.Sandbox] {
|
||||
syscalls[id] = true
|
||||
}
|
||||
broken, tooLong := 0, 0
|
||||
for key, rec := range mgr.corpusDB.Records {
|
||||
p, err := mgr.target.Deserialize(rec.Val, prog.NonStrict)
|
||||
@ -489,7 +486,7 @@ func (mgr *Manager) loadCorpus() {
|
||||
|
||||
disabled := false
|
||||
for _, c := range p.Calls {
|
||||
if !syscalls[c.Meta.ID] {
|
||||
if !mgr.targetEnabledSyscalls[c.Meta] {
|
||||
disabled = true
|
||||
break
|
||||
}
|
||||
@ -1008,7 +1005,7 @@ func (mgr *Manager) fuzzerConnect() ([]rpctype.RPCInput, BugFrames) {
|
||||
return corpus, BugFrames{memoryLeaks: memoryLeakFrames, dataRaces: dataRaceFrames}
|
||||
}
|
||||
|
||||
func (mgr *Manager) machineChecked(a *rpctype.CheckArgs) {
|
||||
func (mgr *Manager) machineChecked(a *rpctype.CheckArgs, enabledSyscalls map[*prog.Syscall]bool) {
|
||||
mgr.mu.Lock()
|
||||
defer mgr.mu.Unlock()
|
||||
if len(mgr.cfg.EnabledSyscalls) != 0 && len(a.DisabledCalls[mgr.cfg.Sandbox]) != 0 {
|
||||
@ -1016,7 +1013,7 @@ func (mgr *Manager) machineChecked(a *rpctype.CheckArgs) {
|
||||
for _, dc := range a.DisabledCalls[mgr.cfg.Sandbox] {
|
||||
disabled[mgr.target.Syscalls[dc.ID].Name] = dc.Reason
|
||||
}
|
||||
for _, id := range mgr.enabledSyscalls {
|
||||
for _, id := range mgr.configEnabledSyscalls {
|
||||
name := mgr.target.Syscalls[id].Name
|
||||
if reason := disabled[name]; reason != "" {
|
||||
log.Logf(0, "disabling %v: %v", name, reason)
|
||||
@ -1027,12 +1024,12 @@ func (mgr *Manager) machineChecked(a *rpctype.CheckArgs) {
|
||||
log.Fatalf("machine check: %v", a.Error)
|
||||
}
|
||||
log.Logf(0, "machine check:")
|
||||
log.Logf(0, "%-24v: %v/%v", "syscalls",
|
||||
len(a.EnabledCalls[mgr.cfg.Sandbox]), len(mgr.target.Syscalls))
|
||||
log.Logf(0, "%-24v: %v/%v", "syscalls", len(enabledSyscalls), len(mgr.target.Syscalls))
|
||||
for _, feat := range a.Features.Supported() {
|
||||
log.Logf(0, "%-24v: %v", feat.Name, feat.Reason)
|
||||
}
|
||||
mgr.checkResult = a
|
||||
mgr.targetEnabledSyscalls = enabledSyscalls
|
||||
mgr.loadCorpus()
|
||||
mgr.firstConnect = time.Now()
|
||||
}
|
||||
|
@ -18,12 +18,13 @@ import (
|
||||
)
|
||||
|
||||
type RPCServer struct {
|
||||
mgr RPCManagerView
|
||||
target *prog.Target
|
||||
enabledSyscalls []int
|
||||
stats *Stats
|
||||
sandbox string
|
||||
batchSize int
|
||||
mgr RPCManagerView
|
||||
target *prog.Target
|
||||
configEnabledSyscalls []int
|
||||
targetEnabledSyscalls map[*prog.Syscall]bool
|
||||
stats *Stats
|
||||
sandbox string
|
||||
batchSize int
|
||||
|
||||
mu sync.Mutex
|
||||
fuzzers map[string]*Fuzzer
|
||||
@ -50,7 +51,7 @@ type BugFrames struct {
|
||||
// RPCManagerView restricts interface between RPCServer and Manager.
|
||||
type RPCManagerView interface {
|
||||
fuzzerConnect() ([]rpctype.RPCInput, BugFrames)
|
||||
machineChecked(result *rpctype.CheckArgs)
|
||||
machineChecked(result *rpctype.CheckArgs, enabledSyscalls map[*prog.Syscall]bool)
|
||||
newInput(inp rpctype.RPCInput, sign signal.Signal) bool
|
||||
candidateBatch(size int) []rpctype.RPCCandidate
|
||||
rotateCorpus() bool
|
||||
@ -58,13 +59,13 @@ type RPCManagerView interface {
|
||||
|
||||
func startRPCServer(mgr *Manager) (int, error) {
|
||||
serv := &RPCServer{
|
||||
mgr: mgr,
|
||||
target: mgr.target,
|
||||
enabledSyscalls: mgr.enabledSyscalls,
|
||||
stats: mgr.stats,
|
||||
sandbox: mgr.cfg.Sandbox,
|
||||
fuzzers: make(map[string]*Fuzzer),
|
||||
rnd: rand.New(rand.NewSource(time.Now().UnixNano())),
|
||||
mgr: mgr,
|
||||
target: mgr.target,
|
||||
configEnabledSyscalls: mgr.configEnabledSyscalls,
|
||||
stats: mgr.stats,
|
||||
sandbox: mgr.cfg.Sandbox,
|
||||
fuzzers: make(map[string]*Fuzzer),
|
||||
rnd: rand.New(rand.NewSource(time.Now().UnixNano())),
|
||||
}
|
||||
serv.batchSize = 5
|
||||
if serv.batchSize < mgr.cfg.Procs {
|
||||
@ -95,7 +96,7 @@ func (serv *RPCServer) Connect(a *rpctype.ConnectArgs, r *rpctype.ConnectRes) er
|
||||
serv.fuzzers[a.Name] = f
|
||||
r.MemoryLeakFrames = bugFrames.memoryLeaks
|
||||
r.DataRaceFrames = bugFrames.dataRaces
|
||||
r.EnabledCalls = serv.enabledSyscalls
|
||||
r.EnabledCalls = serv.configEnabledSyscalls
|
||||
r.GitRevision = prog.GitRevision
|
||||
r.TargetRevision = serv.target.Revision
|
||||
// TODO: temporary disabled b/c we suspect this negatively affects fuzzing.
|
||||
@ -195,14 +196,14 @@ func (serv *RPCServer) Check(a *rpctype.CheckArgs, r *int) error {
|
||||
if serv.checkResult != nil {
|
||||
return nil
|
||||
}
|
||||
serv.mgr.machineChecked(a)
|
||||
serv.targetEnabledSyscalls = make(map[*prog.Syscall]bool)
|
||||
for _, call := range a.EnabledCalls[serv.sandbox] {
|
||||
serv.targetEnabledSyscalls[serv.target.Syscalls[call]] = true
|
||||
}
|
||||
serv.mgr.machineChecked(a, serv.targetEnabledSyscalls)
|
||||
a.DisabledCalls = nil
|
||||
serv.checkResult = a
|
||||
calls := make(map[*prog.Syscall]bool)
|
||||
for _, call := range a.EnabledCalls[serv.sandbox] {
|
||||
calls[serv.target.Syscalls[call]] = true
|
||||
}
|
||||
serv.rotator = prog.MakeRotator(serv.target, calls, serv.rnd)
|
||||
serv.rotator = prog.MakeRotator(serv.target, serv.targetEnabledSyscalls, serv.rnd)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -220,6 +221,12 @@ func (serv *RPCServer) NewInput(a *rpctype.NewInputArgs, r *int) error {
|
||||
log.Logf(0, "rejecting too long program from fuzzer: %v calls\n%s", len(p.Calls), a.RPCInput.Prog)
|
||||
return nil
|
||||
}
|
||||
for _, call := range p.Calls {
|
||||
if !serv.targetEnabledSyscalls[call.Meta] {
|
||||
log.Logf(0, "rejecting program with disabled call %v:\n%s", call.Meta.Name, a.RPCInput.Prog)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
serv.mu.Lock()
|
||||
defer serv.mu.Unlock()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user