aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-07-26 19:38:24 +0200
committerDmitry Vyukov <dvyukov@google.com>2018-07-27 10:22:23 +0200
commitb25fc7b83119e8dca728a199fd92e24dd4c33fa4 (patch)
tree15e95c4062be3f23ab8f66c05e33465d40c1d870
parent9d92841b4e4d0ac0f97f983cd90087323f27c26c (diff)
pkg/csource: add option to trace syscall results
This will be needed for testing of generated programs.
-rw-r--r--executor/common.h11
-rw-r--r--pkg/csource/common.go6
-rw-r--r--pkg/csource/csource.go23
-rw-r--r--pkg/csource/generated.go11
-rw-r--r--pkg/csource/options.go17
-rw-r--r--pkg/csource/options_test.go5
-rw-r--r--tools/syz-prog2c/prog2c.go7
7 files changed, 64 insertions, 16 deletions
diff --git a/executor/common.h b/executor/common.h
index 9e6545926..1b9afd074 100644
--- a/executor/common.h
+++ b/executor/common.h
@@ -21,6 +21,10 @@
#include <stdlib.h>
#include <string.h>
+#if SYZ_TRACE
+#include <errno.h>
+#endif
+
#if SYZ_EXECUTOR && !GOOS_linux
#include <unistd.h>
NORETURN void doexit(int status)
@@ -396,6 +400,9 @@ static void loop()
if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {
}
#endif
+#if SYZ_TRACE
+ printf("### start\n");
+#endif
int call, thread;
#if SYZ_COLLIDE
int collide = 0;
@@ -470,7 +477,11 @@ static void loop()
fail("pipe failed");
#endif
int iter;
+#if SYZ_REPEAT_TIMES
+ for (iter = 0; iter < [[REPEAT_TIMES]]; iter++) {
+#else
for (iter = 0;; iter++) {
+#endif
#if SYZ_EXECUTOR || SYZ_USE_TMP_DIR
// Create a new private work dir for this test (removed at the end of the loop).
char cwdbuf[32];
diff --git a/pkg/csource/common.go b/pkg/csource/common.go
index ebc085c7a..a03fba056 100644
--- a/pkg/csource/common.go
+++ b/pkg/csource/common.go
@@ -95,6 +95,9 @@ func defineList(p, mmapProg *prog.Prog, opts Options) ([]string, error) {
if opts.Repeat {
defines = append(defines, "SYZ_REPEAT")
}
+ if opts.RepeatTimes > 1 {
+ defines = append(defines, "SYZ_REPEAT_TIMES")
+ }
if opts.Procs > 1 {
defines = append(defines, "SYZ_PROCS")
}
@@ -122,6 +125,9 @@ func defineList(p, mmapProg *prog.Prog, opts Options) ([]string, error) {
if opts.Repro {
defines = append(defines, "SYZ_REPRO")
}
+ if opts.Trace {
+ defines = append(defines, "SYZ_TRACE")
+ }
for _, c := range p.Calls {
defines = append(defines, "__NR_"+c.Meta.CallName)
}
diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go
index 66958f22b..895856ea3 100644
--- a/pkg/csource/csource.go
+++ b/pkg/csource/csource.go
@@ -27,13 +27,13 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) {
calls: make(map[string]uint64),
}
- calls, vars, err := ctx.generateProgCalls(ctx.p)
+ calls, vars, err := ctx.generateProgCalls(ctx.p, opts.Trace)
if err != nil {
return nil, err
}
mmapProg := p.Target.GenerateUberMmapProg()
- mmapCalls, _, err := ctx.generateProgCalls(mmapProg)
+ mmapCalls, _, err := ctx.generateProgCalls(mmapProg, false)
if err != nil {
return nil, err
}
@@ -60,6 +60,7 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) {
}
replacements := map[string]string{
"PROCS": fmt.Sprint(opts.Procs),
+ "REPEAT_TIMES": fmt.Sprint(opts.RepeatTimes),
"NUM_CALLS": fmt.Sprint(len(p.Calls)),
"MMAP_DATA": strings.Join(mmapCalls, ""),
"SYSCALL_DEFINES": ctx.generateSyscallDefines(),
@@ -94,17 +95,20 @@ func (ctx *context) generateSyscalls(calls []string, hasVars bool) string {
opts := ctx.opts
buf := new(bytes.Buffer)
if !opts.Threaded && !opts.Collide {
- if hasVars {
+ if hasVars || opts.Trace {
fmt.Fprintf(buf, "\tlong res = 0;\n")
}
if opts.Repro {
fmt.Fprintf(buf, "\tif (write(1, \"executing program\\n\", sizeof(\"executing program\\n\") - 1)) {}\n")
}
+ if opts.Trace {
+ fmt.Fprintf(buf, "\tprintf(\"### start\\n\");\n")
+ }
for _, c := range calls {
fmt.Fprintf(buf, "%s", c)
}
} else {
- if hasVars {
+ if hasVars || opts.Trace {
fmt.Fprintf(buf, "\tlong res;")
}
fmt.Fprintf(buf, "\tswitch (call) {\n")
@@ -145,7 +149,7 @@ func (ctx *context) generateSyscallDefines() string {
return buf.String()
}
-func (ctx *context) generateProgCalls(p *prog.Prog) ([]string, []uint64, error) {
+func (ctx *context) generateProgCalls(p *prog.Prog, trace bool) ([]string, []uint64, error) {
exec := make([]byte, prog.ExecBufferSize)
progSize, err := p.SerializeForExec(exec)
if err != nil {
@@ -155,11 +159,11 @@ func (ctx *context) generateProgCalls(p *prog.Prog) ([]string, []uint64, error)
if err != nil {
return nil, nil, err
}
- calls, vars := ctx.generateCalls(decoded)
+ calls, vars := ctx.generateCalls(decoded, trace)
return calls, vars, nil
}
-func (ctx *context) generateCalls(p prog.ExecProg) ([]string, []uint64) {
+func (ctx *context) generateCalls(p prog.ExecProg, trace bool) ([]string, []uint64) {
var calls []string
csumSeq := 0
for ci, call := range p.Calls {
@@ -185,7 +189,7 @@ func (ctx *context) generateCalls(p prog.ExecProg) ([]string, []uint64) {
if emitCall {
native := ctx.sysTarget.SyscallNumbers && !strings.HasPrefix(callName, "syz_")
fmt.Fprintf(w, "\t")
- if resCopyout || argCopyout {
+ if resCopyout || argCopyout || trace {
fmt.Fprintf(w, "res = ")
}
if native {
@@ -219,6 +223,9 @@ func (ctx *context) generateCalls(p prog.ExecProg) ([]string, []uint64) {
}
}
fmt.Fprintf(w, ");\n")
+ if trace {
+ fmt.Fprintf(w, "\tprintf(\"### call=%v errno=%%d\\n\", res == -1 ? errno : 0);\n", ci)
+ }
}
// Copyout.
diff --git a/pkg/csource/generated.go b/pkg/csource/generated.go
index 7cd6f8777..7be8ca329 100644
--- a/pkg/csource/generated.go
+++ b/pkg/csource/generated.go
@@ -15,6 +15,10 @@ var commonHeader = `
#include <stdlib.h>
#include <string.h>
+#if SYZ_TRACE
+#include <errno.h>
+#endif
+
#if SYZ_EXECUTOR && !GOOS_linux
#include <unistd.h>
NORETURN void doexit(int status)
@@ -3613,6 +3617,9 @@ static void loop()
if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {
}
#endif
+#if SYZ_TRACE
+ printf("### start\n");
+#endif
int call, thread;
#if SYZ_COLLIDE
int collide = 0;
@@ -3684,7 +3691,11 @@ static void loop()
fail("pipe failed");
#endif
int iter;
+#if SYZ_REPEAT_TIMES
+ for (iter = 0; iter < [[REPEAT_TIMES]]; iter++) {
+#else
for (iter = 0;; iter++) {
+#endif
#if SYZ_EXECUTOR || SYZ_USE_TMP_DIR
char cwdbuf[32];
sprintf(cwdbuf, "./%d", iter);
diff --git a/pkg/csource/options.go b/pkg/csource/options.go
index e60554120..a312c5db7 100644
--- a/pkg/csource/options.go
+++ b/pkg/csource/options.go
@@ -15,11 +15,12 @@ import (
// Options control various aspects of source generation.
// Dashboard also provides serialized Options along with syzkaller reproducers.
type Options struct {
- Threaded bool `json:"threaded,omitempty"`
- Collide bool `json:"collide,omitempty"`
- Repeat bool `json:"repeat,omitempty"`
- Procs int `json:"procs"`
- Sandbox string `json:"sandbox"`
+ Threaded bool `json:"threaded,omitempty"`
+ Collide bool `json:"collide,omitempty"`
+ Repeat bool `json:"repeat,omitempty"`
+ RepeatTimes int `json:"repeat_times,omitempty"` // if non-0, repeat that many times
+ Procs int `json:"procs"`
+ Sandbox string `json:"sandbox"`
Fault bool `json:"fault,omitempty"` // inject fault into FaultCall/FaultNth
FaultCall int `json:"fault_call,omitempty"`
@@ -34,8 +35,9 @@ type Options struct {
HandleSegv bool `json:"segv,omitempty"`
// Generate code for use with repro package to prints log messages,
- // which allows to distinguish between a hang and an absent crash.
+ // which allows to detect hangs.
Repro bool `json:"repro,omitempty"`
+ Trace bool `json:"trace,omitempty"`
}
// Check checks if the opts combination is valid or not.
@@ -101,6 +103,9 @@ func (opts Options) Check(OS string) error {
if opts.ResetNet && !opts.Repeat {
return errors.New("ResetNet without Repeat")
}
+ if !opts.Repeat && opts.RepeatTimes != 0 && opts.RepeatTimes != 1 {
+ return errors.New("RepeatTimes without Repeat")
+ }
return nil
}
diff --git a/pkg/csource/options_test.go b/pkg/csource/options_test.go
index f43f2582e..ad86f8786 100644
--- a/pkg/csource/options_test.go
+++ b/pkg/csource/options_test.go
@@ -149,6 +149,11 @@ func enumerateField(OS string, opt Options, field int) []Options {
fld.SetInt(procs)
opts = append(opts, opt)
}
+ } else if fldName == "RepeatTimes" {
+ for _, times := range []int64{0, 10} {
+ fld.SetInt(times)
+ opts = append(opts, opt)
+ }
} else if fldName == "FaultCall" {
opts = append(opts, opt)
} else if fldName == "FaultNth" {
diff --git a/tools/syz-prog2c/prog2c.go b/tools/syz-prog2c/prog2c.go
index 9d89e8241..6abbd68b4 100644
--- a/tools/syz-prog2c/prog2c.go
+++ b/tools/syz-prog2c/prog2c.go
@@ -21,7 +21,7 @@ var (
flagBuild = flag.Bool("build", false, "also build the generated program")
flagThreaded = flag.Bool("threaded", false, "create threaded program")
flagCollide = flag.Bool("collide", false, "create collide program")
- flagRepeat = flag.Bool("repeat", false, "repeat program infinitely or not")
+ flagRepeat = flag.Int("repeat", 1, "repeat program that many times (<=0 - infinitely)")
flagProcs = flag.Int("procs", 1, "number of parallel processes")
flagSandbox = flag.String("sandbox", "", "sandbox to use (none, setuid, namespace)")
flagProg = flag.String("prog", "", "file with program to convert (required)")
@@ -33,6 +33,7 @@ var (
flagNetdev = flag.Bool("netdev", false, "setup various net devices")
flagResetNet = flag.Bool("resetnet", false, "reset net namespace after each test")
flagHandleSegv = flag.Bool("segv", false, "catch and ignore SIGSEGV")
+ flagTrace = flag.Bool("trace", false, "trace syscall results")
)
func main() {
@@ -59,7 +60,8 @@ func main() {
opts := csource.Options{
Threaded: *flagThreaded,
Collide: *flagCollide,
- Repeat: *flagRepeat,
+ Repeat: *flagRepeat != 1,
+ RepeatTimes: *flagRepeat,
Procs: *flagProcs,
Sandbox: *flagSandbox,
Fault: *flagFaultCall >= 0,
@@ -72,6 +74,7 @@ func main() {
ResetNet: *flagResetNet,
HandleSegv: *flagHandleSegv,
Repro: false,
+ Trace: *flagTrace,
}
src, err := csource.Write(p, opts)
if err != nil {