aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pkg/fuzzer/fuzzer.go8
-rw-r--r--pkg/fuzzer/job.go9
-rw-r--r--pkg/rpctype/rpctype.go15
-rw-r--r--pkg/signal/signal.go9
-rw-r--r--syz-fuzzer/fuzzer.go35
-rw-r--r--syz-fuzzer/fuzzer_test.go52
-rw-r--r--syz-manager/rpc.go13
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,
}
}