aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2022-04-01 13:16:03 +0000
committerAleksandr Nogikh <wp32pw@gmail.com>2022-04-29 17:16:33 +0200
commit2d51d57a71659b063ddcb21cc50845d05d39708b (patch)
tree6662e29b20177356ebbc0a4658890e43c39e1e78 /pkg
parent33d1aba90b07c4319e1617be24f6f6dfd1b71d5e (diff)
all: run strace on each found reproducer
If `strace_bin` is specified, syzkaller will invoke a reproducer with it and save the output. This should help in debugging. If syz-manager is attached to a dashboard, upload the strace-powered output and report.
Diffstat (limited to 'pkg')
-rw-r--r--pkg/instance/execprog.go26
-rw-r--r--pkg/mgrconfig/config.go5
-rw-r--r--pkg/mgrconfig/load.go6
-rw-r--r--pkg/repro/strace.go67
4 files changed, 104 insertions, 0 deletions
diff --git a/pkg/instance/execprog.go b/pkg/instance/execprog.go
index 1d775c22c..f6f9bfa01 100644
--- a/pkg/instance/execprog.go
+++ b/pkg/instance/execprog.go
@@ -13,6 +13,7 @@ import (
"github.com/google/syzkaller/pkg/osutil"
"github.com/google/syzkaller/pkg/report"
"github.com/google/syzkaller/prog"
+ "github.com/google/syzkaller/sys/targets"
"github.com/google/syzkaller/vm"
)
@@ -23,6 +24,7 @@ type OptionalConfig struct {
Logf ExecutorLogger
OldFlagsCompatMode bool
BeforeContextLen int
+ StraceBin string
}
type ExecProgInstance struct {
@@ -62,6 +64,14 @@ func SetupExecProg(vmInst *vm.Instance, mgrCfg *mgrconfig.Config, reporter *repo
}
if opt != nil {
ret.OptionalConfig = *opt
+ if ret.StraceBin != "" {
+ var err error
+ ret.StraceBin, err = vmInst.Copy(ret.StraceBin)
+ if err != nil {
+ vmInst.Close()
+ return nil, &TestError{Title: fmt.Sprintf("failed to copy strace bin: %v", err)}
+ }
+ }
}
if ret.Logf == nil {
ret.Logf = func(int, string, ...interface{}) {}
@@ -87,6 +97,19 @@ func CreateExecProgInstance(vmPool *vm.Pool, vmIndex int, mgrCfg *mgrconfig.Conf
}
func (inst *ExecProgInstance) runCommand(command string, duration time.Duration) (*RunResult, error) {
+ var prefixOutput []byte
+ if inst.StraceBin != "" {
+ filterCalls := ""
+ switch inst.mgrCfg.SysTarget.OS {
+ case targets.Linux:
+ // wait4 and nanosleep generate a lot of noise, especially when running syz-executor.
+ // We cut them on the VM side in order to decrease load on the network and to use
+ // the limited buffer size wisely.
+ filterCalls = ` -e \!wait4,clock_nanosleep,nanosleep`
+ }
+ command = inst.StraceBin + filterCalls + ` -s 100 -x -f ` + command
+ prefixOutput = []byte(fmt.Sprintf("%s\n\n<...>\n", command))
+ }
outc, errc, err := inst.VMInstance.Run(duration, nil, command)
if err != nil {
return nil, fmt.Errorf("failed to run command in VM: %v", err)
@@ -95,6 +118,9 @@ func (inst *ExecProgInstance) runCommand(command string, duration time.Duration)
ExecutionResult: *inst.VMInstance.MonitorExecutionRaw(outc, errc,
inst.reporter, inst.ExitCondition, inst.BeforeContextLen),
}
+ if len(prefixOutput) > 0 {
+ result.RawOutput = append(prefixOutput, result.RawOutput...)
+ }
if result.Report == nil {
inst.Logf(2, "program did not crash")
} else {
diff --git a/pkg/mgrconfig/config.go b/pkg/mgrconfig/config.go
index c13e6f452..20a0b7b57 100644
--- a/pkg/mgrconfig/config.go
+++ b/pkg/mgrconfig/config.go
@@ -168,6 +168,11 @@ type Config struct {
// Regexps are matched against bug title, guilty file and maintainer emails.
Interests []string `json:"interests,omitempty"`
+ // Path to the strace binary compiled for the target architecture.
+ // If set, for each reproducer syzkaller will run it once more under strace and save
+ // the output.
+ StraceBin string `json:"strace_bin"`
+
// Type of virtual machine to use, e.g. "qemu", "gce", "android", "isolated", etc.
Type string `json:"type"`
// VM-type-specific parameters.
diff --git a/pkg/mgrconfig/load.go b/pkg/mgrconfig/load.go
index c9528b38a..2b49d0cbd 100644
--- a/pkg/mgrconfig/load.go
+++ b/pkg/mgrconfig/load.go
@@ -256,6 +256,12 @@ func (cfg *Config) completeBinaries() error {
if cfg.ExecutorBin != "" && !osutil.IsExist(cfg.ExecutorBin) {
return fmt.Errorf("bad config syzkaller param: can't find %v", cfg.ExecutorBin)
}
+ if cfg.StraceBin != "" {
+ if !osutil.IsExist(cfg.StraceBin) {
+ return fmt.Errorf("bad config param strace_bin: can't find %v", cfg.StraceBin)
+ }
+ cfg.StraceBin = osutil.Abs(cfg.StraceBin)
+ }
return nil
}
diff --git a/pkg/repro/strace.go b/pkg/repro/strace.go
new file mode 100644
index 000000000..07c3ea025
--- /dev/null
+++ b/pkg/repro/strace.go
@@ -0,0 +1,67 @@
+// Copyright 2022 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 repro
+
+import (
+ "fmt"
+
+ "github.com/google/syzkaller/pkg/instance"
+ "github.com/google/syzkaller/pkg/log"
+ "github.com/google/syzkaller/pkg/mgrconfig"
+ "github.com/google/syzkaller/pkg/report"
+ "github.com/google/syzkaller/vm"
+)
+
+type StraceResult struct {
+ Report *report.Report
+ Output []byte
+ Error error
+}
+
+const (
+ straceOutputLogSize = 2048 << 10
+)
+
+func RunStrace(result *Result, cfg *mgrconfig.Config, reporter *report.Reporter,
+ vmPool *vm.Pool, vmIndex int) *StraceResult {
+ if cfg.StraceBin == "" {
+ return straceFailed(fmt.Errorf("strace binary is not set in the config"))
+ }
+ inst, err := instance.CreateExecProgInstance(vmPool, vmIndex, cfg, reporter,
+ &instance.OptionalConfig{
+ StraceBin: cfg.StraceBin,
+ BeforeContextLen: straceOutputLogSize,
+ })
+ if err != nil {
+ return straceFailed(fmt.Errorf("failed to set up instance: %v", err))
+ }
+ defer inst.VMInstance.Close()
+
+ var runRes *instance.RunResult
+ if result.CRepro {
+ log.Logf(1, "running C repro under strace")
+ runRes, err = inst.RunCProg(result.Prog, result.Duration, result.Opts)
+ } else {
+ log.Logf(1, "running syz repro under strace")
+ runRes, err = inst.RunSyzProg(result.Prog.Serialize(), result.Duration, result.Opts)
+ }
+ if err != nil {
+ return straceFailed(fmt.Errorf("failed to generate strace log: %v", err))
+ }
+ return &StraceResult{
+ Report: runRes.Report,
+ Output: runRes.RawOutput,
+ }
+}
+
+func straceFailed(err error) *StraceResult {
+ return &StraceResult{Error: err}
+}
+
+func (strace *StraceResult) IsSameBug(repro *Result) bool {
+ if strace == nil || strace.Report == nil || repro.Report == nil {
+ return false
+ }
+ return strace.Report.Title == repro.Report.Title
+}