diff options
| -rw-r--r-- | pkg/fuzzer/fuzzer.go | 8 | ||||
| -rw-r--r-- | pkg/fuzzer/job.go | 9 | ||||
| -rw-r--r-- | pkg/rpctype/rpctype.go | 15 | ||||
| -rw-r--r-- | pkg/signal/signal.go | 9 | ||||
| -rw-r--r-- | syz-fuzzer/fuzzer.go | 35 | ||||
| -rw-r--r-- | syz-fuzzer/fuzzer_test.go | 52 | ||||
| -rw-r--r-- | syz-manager/rpc.go | 13 |
7 files changed, 53 insertions, 88 deletions
diff --git a/pkg/fuzzer/fuzzer.go b/pkg/fuzzer/fuzzer.go index 2663d7b60..a5b338b13 100644 --- a/pkg/fuzzer/fuzzer.go +++ b/pkg/fuzzer/fuzzer.go @@ -89,7 +89,10 @@ type Request struct { NeedRawCover bool NeedSignal rpctype.SignalType NeedHints bool - SignalFilter signal.Signal // If specified, the resulting signal MAY be a subset of it. + // If specified, the resulting signal for call SignalFilterCall + // will include subset of it even if it's not new. + SignalFilter signal.Signal + SignalFilterCall int // Fields that are only relevant within pkg/fuzzer. flags ProgTypes stat *stats.Val @@ -249,6 +252,9 @@ func (fuzzer *Fuzzer) pushExec(req *Request, prio priority) { if req.NeedHints && (req.NeedCover || req.NeedSignal != rpctype.NoSignal) { panic("Request.NeedHints is mutually exclusive with other fields") } + if req.SignalFilter != nil && req.NeedSignal != rpctype.NewSignal { + panic("SignalFilter must be used with NewSignal") + } fuzzer.nextExec.push(&priorityQueueItem[*Request]{ value: req, prio: prio, }) diff --git a/pkg/fuzzer/job.go b/pkg/fuzzer/job.go index ede1f1a57..b5bb2aab1 100644 --- a/pkg/fuzzer/job.go +++ b/pkg/fuzzer/job.go @@ -237,10 +237,11 @@ func (job *triageJob) minimize(fuzzer *Fuzzer, newSignal signal.Signal) (stop bo } for i := 0; i < minimizeAttempts; i++ { result := fuzzer.exec(job, &Request{ - Prog: p1, - NeedSignal: rpctype.AllSignal, - SignalFilter: newSignal, - stat: fuzzer.statExecMinimize, + Prog: p1, + NeedSignal: rpctype.NewSignal, + SignalFilter: newSignal, + SignalFilterCall: call1, + stat: fuzzer.statExecMinimize, }) if result.Stop { stop = true diff --git a/pkg/rpctype/rpctype.go b/pkg/rpctype/rpctype.go index 1130d11b7..7e15ba69c 100644 --- a/pkg/rpctype/rpctype.go +++ b/pkg/rpctype/rpctype.go @@ -25,13 +25,14 @@ const ( // ExecutionRequest describes the task of executing a particular program. // Corresponds to Fuzzer.Request. type ExecutionRequest struct { - ID int64 - ProgData []byte - NeedCover bool - NeedRawCover bool - NeedHints bool - NeedSignal SignalType - SignalFilter signal.Signal + ID int64 + ProgData []byte + NeedCover bool + NeedRawCover bool + NeedHints bool + NeedSignal SignalType + SignalFilter signal.Signal + SignalFilterCall int } // ExecutionResult is sent after ExecutionRequest is completed. diff --git a/pkg/signal/signal.go b/pkg/signal/signal.go index 48686de54..10a1ef0cb 100644 --- a/pkg/signal/signal.go +++ b/pkg/signal/signal.go @@ -159,11 +159,14 @@ func (s Signal) RandomSubset(r *rand.Rand, size int) Signal { return ret } -// FilterRaw returns a subset of original raw elements that coincides with the one in Signal. -func (s Signal) FilterRaw(raw []uint32) []uint32 { +// FilterRaw returns a subset of original raw elements that either are not present in ignore, +// or coincides with the one in alwaysTake. +func FilterRaw(raw []uint32, ignore, alwaysTake Signal) []uint32 { var ret []uint32 for _, e := range raw { - if _, ok := s[elemType(e)]; ok { + if _, ok := alwaysTake[elemType(e)]; ok { + ret = append(ret, e) + } else if _, ok := ignore[elemType(e)]; !ok { ret = append(ret, e) } } diff --git a/syz-fuzzer/fuzzer.go b/syz-fuzzer/fuzzer.go index 52e8de1a5..eb44ff2ae 100644 --- a/syz-fuzzer/fuzzer.go +++ b/syz-fuzzer/fuzzer.go @@ -381,11 +381,7 @@ func (tool *FuzzerTool) convertExecutionResult(res executionResult) rpctype.Exec ret := rpctype.ExecutionResult{ID: res.ID} if res.info != nil { if res.NeedSignal == rpctype.NewSignal { - tool.diffMaxSignal(res.info) - } - if res.SignalFilter != nil { - // TODO: we can filter without maps if req.SignalFilter is sorted. - filterProgInfo(res.info, res.SignalFilter) + tool.diffMaxSignal(res.info, res.SignalFilter, res.SignalFilterCall) } ret.Info = *res.info } @@ -416,29 +412,24 @@ func (tool *FuzzerTool) deserializeInput(inp []byte) *prog.Prog { return p } -// The linter is too aggressive. -// nolint: dupl -func filterProgInfo(info *ipc.ProgInfo, mask signal.Signal) { - info.Extra.Signal = mask.FilterRaw(info.Extra.Signal) - for i := 0; i < len(info.Calls); i++ { - info.Calls[i].Signal = mask.FilterRaw(info.Calls[i].Signal) - } +func (tool *FuzzerTool) diffMaxSignal(info *ipc.ProgInfo, mask signal.Signal, maskCall int) { + tool.signalMu.RLock() + defer tool.signalMu.RUnlock() + diffMaxSignal(info, tool.maxSignal, mask, maskCall) } -// The linter is too aggressive. -// nolint: dupl -func diffProgInfo(info *ipc.ProgInfo, base signal.Signal) { - info.Extra.Signal = base.DiffFromRaw(info.Extra.Signal) +func diffMaxSignal(info *ipc.ProgInfo, max, mask signal.Signal, maskCall int) { + info.Extra.Signal = diffCallSignal(info.Extra.Signal, max, mask, -1, maskCall) for i := 0; i < len(info.Calls); i++ { - info.Calls[i].Signal = base.DiffFromRaw(info.Calls[i].Signal) + info.Calls[i].Signal = diffCallSignal(info.Calls[i].Signal, max, mask, i, maskCall) } } -func (tool *FuzzerTool) diffMaxSignal(info *ipc.ProgInfo) { - tool.signalMu.RLock() - defer tool.signalMu.RUnlock() - - diffProgInfo(info, tool.maxSignal) +func diffCallSignal(raw []uint32, max, mask signal.Signal, call, maskCall int) []uint32 { + if mask != nil && call == maskCall { + return signal.FilterRaw(raw, max, mask) + } + return max.DiffFromRaw(raw) } func (tool *FuzzerTool) updateMaxSignal(add, drop []uint32) { diff --git a/syz-fuzzer/fuzzer_test.go b/syz-fuzzer/fuzzer_test.go index 9ce5514b6..d43b7bc74 100644 --- a/syz-fuzzer/fuzzer_test.go +++ b/syz-fuzzer/fuzzer_test.go @@ -11,17 +11,17 @@ import ( "github.com/stretchr/testify/assert" ) -// nolint: dupl func TestFilterProgInfo(t *testing.T) { + max := signal.FromRaw([]uint32{5, 6, 7}, 0) mask := signal.FromRaw([]uint32{2, 4, 6, 8}, 0) info := ipc.ProgInfo{ Calls: []ipc.CallInfo{ { - Signal: []uint32{1, 2, 3}, + Signal: []uint32{1, 2, 3, 5, 6}, Cover: []uint32{1, 2, 3}, }, { - Signal: []uint32{2, 3, 4}, + Signal: []uint32{2, 3, 4, 6, 7}, Cover: []uint32{2, 3, 4}, }, }, @@ -30,59 +30,21 @@ func TestFilterProgInfo(t *testing.T) { Cover: []uint32{3, 4, 5}, }, } - filterProgInfo(&info, mask) + diffMaxSignal(&info, max, mask, 1) assert.Equal(t, ipc.ProgInfo{ Calls: []ipc.CallInfo{ { - Signal: []uint32{2}, - Cover: []uint32{1, 2, 3}, - }, - { - Signal: []uint32{2, 4}, - Cover: []uint32{2, 3, 4}, - }, - }, - Extra: ipc.CallInfo{ - Signal: []uint32{4}, - Cover: []uint32{3, 4, 5}, - }, - }, info) -} - -// nolint: dupl -func TestDiffProgInfo(t *testing.T) { - base := signal.FromRaw([]uint32{0, 1, 2}, 0) - info := ipc.ProgInfo{ - Calls: []ipc.CallInfo{ - { - Signal: []uint32{0, 1, 2}, - Cover: []uint32{0, 1, 2}, - }, - { Signal: []uint32{1, 2, 3}, Cover: []uint32{1, 2, 3}, }, - }, - Extra: ipc.CallInfo{ - Signal: []uint32{2, 3, 4}, - Cover: []uint32{2, 3, 4}, - }, - } - diffProgInfo(&info, base) - assert.Equal(t, ipc.ProgInfo{ - Calls: []ipc.CallInfo{ - { - Signal: nil, - Cover: []uint32{0, 1, 2}, - }, { - Signal: []uint32{3}, - Cover: []uint32{1, 2, 3}, + Signal: []uint32{2, 3, 4, 6}, + Cover: []uint32{2, 3, 4}, }, }, Extra: ipc.CallInfo{ Signal: []uint32{3, 4}, - Cover: []uint32{2, 3, 4}, + Cover: []uint32{3, 4, 5}, }, }, info) } diff --git a/syz-manager/rpc.go b/syz-manager/rpc.go index 4655a1898..3603d3b42 100644 --- a/syz-manager/rpc.go +++ b/syz-manager/rpc.go @@ -358,11 +358,12 @@ func (runner *Runner) newRequest(req *fuzzer.Request) rpctype.ExecutionRequest { } runner.mu.Unlock() return rpctype.ExecutionRequest{ - ID: id, - ProgData: req.Prog.Serialize(), - NeedCover: req.NeedCover, - NeedSignal: req.NeedSignal, - SignalFilter: signalFilter, - NeedHints: req.NeedHints, + ID: id, + ProgData: req.Prog.Serialize(), + NeedCover: req.NeedCover, + NeedSignal: req.NeedSignal, + SignalFilter: signalFilter, + SignalFilterCall: req.SignalFilterCall, + NeedHints: req.NeedHints, } } |
