aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2020-05-12 15:26:07 +0200
committerDmitry Vyukov <dvyukov@google.com>2020-05-12 15:26:07 +0200
commita44eb8f7eadcc16e73055948131b2c56b4fd5272 (patch)
treefd56018398be21abc08d3248db0c0d6509151f04
parent9cea41ad339ff55a0eb50b43b15c73245fa86343 (diff)
syz-manager: more consistently check disabled syscalls
We have program "validity" check duplicated 4 times (initially it was just "does it deserialize?"). Then we added program length and disabled syscall. But some of the sites have only a subset of checks. Factor out program checking procedure into a separate function and use it at all sites.
-rw-r--r--syz-manager/hub.go19
-rw-r--r--syz-manager/manager.go39
-rw-r--r--syz-manager/rpc.go17
3 files changed, 36 insertions, 39 deletions
diff --git a/syz-manager/hub.go b/syz-manager/hub.go
index 51937b536..9028f0233 100644
--- a/syz-manager/hub.go
+++ b/syz-manager/hub.go
@@ -21,7 +21,7 @@ func (mgr *Manager) hubSyncLoop() {
cfg: mgr.cfg,
target: mgr.target,
stats: mgr.stats,
- enabledCalls: mgr.checkResult.EnabledCalls[mgr.cfg.Sandbox],
+ enabledCalls: mgr.targetEnabledSyscalls,
leak: mgr.checkResult.Features[host.FeatureLeak].Enabled,
fresh: mgr.fresh,
hubReproQueue: mgr.hubReproQueue,
@@ -37,7 +37,7 @@ type HubConnector struct {
cfg *mgrconfig.Config
target *prog.Target
stats *Stats
- enabledCalls []int
+ enabledCalls map[*prog.Syscall]bool
leak bool
fresh bool
hubCorpus map[hash.Sig]bool
@@ -80,8 +80,8 @@ func (hc *HubConnector) connect(corpus [][]byte) (*rpctype.RPCClient, error) {
Manager: hc.cfg.Name,
Fresh: hc.fresh,
}
- for _, id := range hc.enabledCalls {
- a.Calls = append(a.Calls, hc.target.Syscalls[id].Name)
+ for call := range hc.enabledCalls {
+ a.Calls = append(a.Calls, call.Name)
}
hubCorpus := make(map[hash.Sig]bool)
for _, inp := range corpus {
@@ -171,8 +171,10 @@ func (hc *HubConnector) processProgs(progs [][]byte) int {
dropped := 0
candidates := make([][]byte, 0, len(progs))
for _, inp := range progs {
- p, err := hc.target.Deserialize(inp, prog.NonStrict)
- if err != nil || len(p.Calls) > prog.MaxCalls {
+ bad, disabled := checkProgram(hc.target, hc.enabledCalls, inp)
+ if bad || disabled {
+ log.Logf(0, "rejecting program from hub (bad=%v, disabled=%v):\n%s",
+ bad, disabled, inp)
dropped++
continue
}
@@ -185,7 +187,10 @@ func (hc *HubConnector) processProgs(progs [][]byte) int {
func (hc *HubConnector) processRepros(repros [][]byte) int {
dropped := 0
for _, repro := range repros {
- if _, err := hc.target.Deserialize(repro, prog.NonStrict); err != nil {
+ bad, disabled := checkProgram(hc.target, hc.enabledCalls, repro)
+ if bad || disabled {
+ log.Logf(0, "rejecting repro from hub (bad=%v, disabled=%v):\n%s",
+ bad, disabled, repro)
dropped++
continue
}
diff --git a/syz-manager/manager.go b/syz-manager/manager.go
index ab1179f95..3e44d24e2 100644
--- a/syz-manager/manager.go
+++ b/syz-manager/manager.go
@@ -470,27 +470,14 @@ func (mgr *Manager) loadCorpus() {
fallthrough
case currentDBVersion:
}
- broken, tooLong := 0, 0
+ broken := 0
for key, rec := range mgr.corpusDB.Records {
- p, err := mgr.target.Deserialize(rec.Val, prog.NonStrict)
- if err != nil {
+ bad, disabled := checkProgram(mgr.target, mgr.targetEnabledSyscalls, rec.Val)
+ if bad {
mgr.corpusDB.Delete(key)
broken++
continue
}
- if len(p.Calls) > prog.MaxCalls {
- mgr.corpusDB.Delete(key)
- tooLong++
- continue
- }
-
- disabled := false
- for _, c := range p.Calls {
- if !mgr.targetEnabledSyscalls[c.Meta] {
- disabled = true
- break
- }
- }
if disabled {
// This program contains a disabled syscall.
// We won't execute it, but remember its hash so
@@ -505,8 +492,8 @@ func (mgr *Manager) loadCorpus() {
})
}
mgr.fresh = len(mgr.corpusDB.Records) == 0
- log.Logf(0, "%-24v: %v (deleted %v broken, %v too long)",
- "corpus", len(mgr.candidates), broken, tooLong)
+ log.Logf(0, "%-24v: %v (deleted %v broken)",
+ "corpus", len(mgr.candidates), broken)
// Now this is ugly.
// We duplicate all inputs in the corpus and shuffle the second part.
@@ -525,6 +512,22 @@ func (mgr *Manager) loadCorpus() {
mgr.phase = phaseLoadedCorpus
}
+func checkProgram(target *prog.Target, enabled map[*prog.Syscall]bool, data []byte) (bad, disabled bool) {
+ p, err := target.Deserialize(data, prog.NonStrict)
+ if err != nil {
+ return true, true
+ }
+ if len(p.Calls) > prog.MaxCalls {
+ return true, true
+ }
+ for _, c := range p.Calls {
+ if !enabled[c.Meta] {
+ return false, true
+ }
+ }
+ return false, false
+}
+
func (mgr *Manager) runInstance(index int) (*Crash, error) {
mgr.checkUsedFiles()
inst, err := mgr.vmPool.Create(index)
diff --git a/syz-manager/rpc.go b/syz-manager/rpc.go
index d734b8da9..6cf979a38 100644
--- a/syz-manager/rpc.go
+++ b/syz-manager/rpc.go
@@ -211,22 +211,11 @@ 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))
- p, err := serv.target.Deserialize(a.RPCInput.Prog, prog.NonStrict)
- if err != nil {
- // This should not happen, but we see such cases episodically (probably corrupted VM memory).
- log.Logf(0, "failed to deserialize program from fuzzer: %v\n%s", err, a.RPCInput.Prog)
- return nil
- }
- if len(p.Calls) > prog.MaxCalls {
- log.Logf(0, "rejecting too long program from fuzzer: %v calls\n%s", len(p.Calls), a.RPCInput.Prog)
+ bad, disabled := checkProgram(serv.target, serv.targetEnabledSyscalls, a.RPCInput.Prog)
+ if bad || disabled {
+ log.Logf(0, "rejecting program from fuzzer (bad=%v, disabled=%v):\n%s", bad, disabled, 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()