aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-09-14 19:25:01 +0200
committerDmitry Vyukov <dvyukov@google.com>2017-09-15 16:02:37 +0200
commit52a33fd516102a98d3753bf69417235b655a68dc (patch)
tree351ab73db934d3b4e4babbe27e8801c659f2631b
parent25f4fe0662f7f3b390d16b2e786f2ba0aa0293f1 (diff)
prog: remove default target and all global state
Now each prog function accepts the desired target explicitly. No global, implicit state involved. This is much cleaner and allows cross-OS/arch testing, etc.
-rw-r--r--pkg/csource/csource.go6
-rw-r--r--pkg/csource/csource_test.go24
-rw-r--r--pkg/host/host.go4
-rw-r--r--pkg/host/host_test.go24
-rw-r--r--pkg/ipc/ipc_test.go11
-rw-r--r--pkg/repro/repro.go6
-rw-r--r--prog/analysis.go8
-rw-r--r--prog/checksum_test.go4
-rw-r--r--prog/clone.go4
-rw-r--r--prog/decl_test.go47
-rw-r--r--prog/encoding.go22
-rw-r--r--prog/encoding_test.go12
-rw-r--r--prog/encodingexec.go26
-rw-r--r--prog/encodingexec_test.go18
-rw-r--r--prog/export_test.go16
-rw-r--r--prog/generation.go10
-rw-r--r--prog/hints.go2
-rw-r--r--prog/mutation.go35
-rw-r--r--prog/mutation_test.go32
-rw-r--r--prog/parse.go4
-rw-r--r--prog/parse_test.go18
-rw-r--r--prog/prio.go44
-rw-r--r--prog/prog.go7
-rw-r--r--prog/prog_test.go32
-rw-r--r--prog/rand.go63
-rw-r--r--prog/resources.go30
-rw-r--r--prog/size.go18
-rw-r--r--prog/size_test.go23
-rw-r--r--prog/target.go60
-rw-r--r--syz-fuzzer/fuzzer.go33
-rw-r--r--syz-manager/html.go7
-rw-r--r--syz-manager/manager.go21
-rw-r--r--syz-manager/mgrconfig/mgrconfig.go11
-rw-r--r--tools/syz-crush/crush.go2
-rw-r--r--tools/syz-execprog/execprog.go5
-rw-r--r--tools/syz-mutate/mutate.go9
-rw-r--r--tools/syz-prog2c/prog2c.go6
-rw-r--r--tools/syz-repro/repro.go2
-rw-r--r--tools/syz-stress/stress.go27
-rw-r--r--tools/syz-upgrade/upgrade.go7
40 files changed, 384 insertions, 356 deletions
diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go
index e1b32e752..8b7c84ad3 100644
--- a/pkg/csource/csource.go
+++ b/pkg/csource/csource.go
@@ -101,7 +101,7 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) {
fmt.Fprint(w, hdr)
fmt.Fprint(w, "\n")
- calls, nvar := generateCalls(exec, opts)
+ calls, nvar := generateCalls(p.Target, exec, opts)
fmt.Fprintf(w, "long r[%v];\n", nvar)
if !opts.Repeat {
@@ -258,7 +258,7 @@ func generateTestFunc(w io.Writer, opts Options, calls []string, name string) {
}
}
-func generateCalls(exec []byte, opts Options) ([]string, int) {
+func generateCalls(target *prog.Target, exec []byte, opts Options) ([]string, int) {
read := func() uint64 {
if len(exec) < 8 {
panic("exec program overflow")
@@ -367,7 +367,7 @@ loop:
fmt.Fprintf(w, "\twrite_file(\"/sys/kernel/debug/fail_futex/ignore-private\", \"N\");\n")
fmt.Fprintf(w, "\tinject_fault(%v);\n", opts.FaultNth)
}
- meta := prog.Syscalls[instr]
+ meta := target.Syscalls[instr]
emitCall := true
if meta.CallName == "syz_test" {
emitCall = false
diff --git a/pkg/csource/csource_test.go b/pkg/csource/csource_test.go
index 941274cb9..c192566e3 100644
--- a/pkg/csource/csource_test.go
+++ b/pkg/csource/csource_test.go
@@ -17,17 +17,17 @@ import (
_ "github.com/google/syzkaller/sys"
)
-func init() {
- prog.SetDefaultTarget("linux", runtime.GOARCH)
-}
-
-func initTest(t *testing.T) (rand.Source, int) {
+func initTest(t *testing.T) (*prog.Target, rand.Source, int) {
t.Parallel()
iters := 1
seed := int64(time.Now().UnixNano())
rs := rand.NewSource(seed)
t.Logf("seed=%v", seed)
- return rs, iters
+ target, err := prog.GetTarget("linux", runtime.GOARCH)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return target, rs, iters
}
func enumerateField(opt Options, field int) []Options {
@@ -89,7 +89,7 @@ func allOptionsPermutations() []Options {
}
func TestOne(t *testing.T) {
- rs, _ := initTest(t)
+ target, rs, _ := initTest(t)
opts := Options{
Threaded: true,
Collide: true,
@@ -99,13 +99,13 @@ func TestOne(t *testing.T) {
Repro: true,
UseTmpDir: true,
}
- p := prog.GenerateAllSyzProg(rs)
+ p := target.GenerateAllSyzProg(rs)
testOne(t, p, opts)
}
func TestOptions(t *testing.T) {
- rs, _ := initTest(t)
- syzProg := prog.GenerateAllSyzProg(rs)
+ target, rs, _ := initTest(t)
+ syzProg := target.GenerateAllSyzProg(rs)
t.Logf("syz program:\n%s\n", syzProg.Serialize())
permutations := allOptionsSingle()
allPermutations := allOptionsPermutations()
@@ -119,10 +119,10 @@ func TestOptions(t *testing.T) {
}
for i, opts := range permutations {
t.Run(fmt.Sprintf("%v", i), func(t *testing.T) {
- rs, iters := initTest(t)
+ target, rs, iters := initTest(t)
t.Logf("opts: %+v", opts)
for i := 0; i < iters; i++ {
- p := prog.Generate(rs, 10, nil)
+ p := target.Generate(rs, 10, nil)
testOne(t, p, opts)
}
testOne(t, syzProg, opts)
diff --git a/pkg/host/host.go b/pkg/host/host.go
index 0fa66dfa4..993db175b 100644
--- a/pkg/host/host.go
+++ b/pkg/host/host.go
@@ -16,7 +16,7 @@ import (
)
// DetectSupportedSyscalls returns list on supported syscalls on host.
-func DetectSupportedSyscalls() (map[*prog.Syscall]bool, error) {
+func DetectSupportedSyscalls(target *prog.Target) (map[*prog.Syscall]bool, error) {
// There are 3 possible strategies:
// 1. Executes all syscalls with presumably invalid arguments and check for ENOprog.
// But not all syscalls are safe to execute. For example, pause will hang,
@@ -29,7 +29,7 @@ func DetectSupportedSyscalls() (map[*prog.Syscall]bool, error) {
kallsyms, _ := ioutil.ReadFile("/proc/kallsyms")
supported := make(map[*prog.Syscall]bool)
- for _, c := range prog.Syscalls {
+ for _, c := range target.Syscalls {
if isSupported(kallsyms, c) {
supported[c] = true
}
diff --git a/pkg/host/host_test.go b/pkg/host/host_test.go
index a9130c094..1c40335d7 100644
--- a/pkg/host/host_test.go
+++ b/pkg/host/host_test.go
@@ -12,19 +12,19 @@ import (
_ "github.com/google/syzkaller/sys"
)
-func init() {
- prog.SetDefaultTarget("linux", runtime.GOARCH)
-}
-
func TestLog(t *testing.T) {
t.Parallel()
+ target, err := prog.GetTarget("linux", runtime.GOARCH)
+ if err != nil {
+ t.Fatal(err)
+ }
// Dump for manual inspection.
- supp, err := DetectSupportedSyscalls()
+ supp, err := DetectSupportedSyscalls(target)
if err != nil {
t.Skipf("skipping: %v", err)
}
t.Logf("unsupported:")
- for _, c := range prog.Syscalls {
+ for _, c := range target.Syscalls {
s, ok := supp[c]
if ok && !s {
t.Fatalf("map contains false value")
@@ -33,9 +33,9 @@ func TestLog(t *testing.T) {
t.Logf("\t%v", c.Name)
}
}
- trans := prog.TransitivelyEnabledCalls(supp)
+ trans := target.TransitivelyEnabledCalls(supp)
t.Logf("transitively unsupported:")
- for _, c := range prog.Syscalls {
+ for _, c := range target.Syscalls {
s, ok := trans[c]
if ok && !s {
t.Fatalf("map contains false value")
@@ -48,7 +48,11 @@ func TestLog(t *testing.T) {
func TestSupportedSyscalls(t *testing.T) {
t.Parallel()
- supp, err := DetectSupportedSyscalls()
+ target, err := prog.GetTarget("linux", runtime.GOARCH)
+ if err != nil {
+ t.Fatal(err)
+ }
+ supp, err := DetectSupportedSyscalls(target)
if err != nil {
t.Skipf("skipping: %v", err)
}
@@ -64,7 +68,7 @@ func TestSupportedSyscalls(t *testing.T) {
"stat",
}
for _, name := range safe {
- c := prog.SyscallMap[name]
+ c := target.SyscallMap[name]
if c == nil {
t.Fatalf("can't find syscall '%v'", name)
}
diff --git a/pkg/ipc/ipc_test.go b/pkg/ipc/ipc_test.go
index ce04a7540..263e94032 100644
--- a/pkg/ipc/ipc_test.go
+++ b/pkg/ipc/ipc_test.go
@@ -19,10 +19,6 @@ import (
const timeout = 10 * time.Second
-func init() {
- prog.SetDefaultTarget("linux", runtime.GOARCH)
-}
-
func buildExecutor(t *testing.T) string {
return buildProgram(t, filepath.FromSlash("../../executor/executor.cc"))
}
@@ -87,6 +83,11 @@ func TestExecute(t *testing.T) {
rs, iters := initTest(t)
flags := []uint64{0, FlagThreaded, FlagThreaded | FlagCollide}
+ target, err := prog.GetTarget("linux", runtime.GOARCH)
+ if err != nil {
+ t.Fatal(err)
+ }
+
bin := buildExecutor(t)
defer os.Remove(bin)
@@ -103,7 +104,7 @@ func TestExecute(t *testing.T) {
defer env.Close()
for i := 0; i < iters/len(flags); i++ {
- p := prog.Generate(rs, 10, nil)
+ p := target.Generate(rs, 10, nil)
opts := &ExecOpts{}
output, _, _, _, err := env.Exec(opts, p)
if err != nil {
diff --git a/pkg/repro/repro.go b/pkg/repro/repro.go
index c3aaa8a22..4787b0262 100644
--- a/pkg/repro/repro.go
+++ b/pkg/repro/repro.go
@@ -65,7 +65,11 @@ func Run(crashLog []byte, cfg *mgrconfig.Config, vmPool *vm.Pool, vmIndexes []in
if len(vmIndexes) == 0 {
return nil, fmt.Errorf("no VMs provided")
}
- entries := prog.ParseLog(crashLog)
+ target, err := prog.GetTarget(cfg.TargetOS, cfg.TargetArch)
+ if err != nil {
+ return nil, err
+ }
+ entries := target.ParseLog(crashLog)
if len(entries) == 0 {
return nil, fmt.Errorf("crash log does not contain any programs")
}
diff --git a/prog/analysis.go b/prog/analysis.go
index 009a15a21..80a127108 100644
--- a/prog/analysis.go
+++ b/prog/analysis.go
@@ -17,6 +17,7 @@ const (
)
type state struct {
+ target *Target
ct *ChoiceTable
files map[string]bool
resources map[string][]Arg
@@ -26,7 +27,7 @@ type state struct {
// analyze analyzes the program p up to but not including call c.
func analyze(ct *ChoiceTable, p *Prog, c *Call) *state {
- s := newState(ct)
+ s := newState(p.Target, ct)
for _, c1 := range p.Calls {
if c1 == c {
break
@@ -36,8 +37,9 @@ func analyze(ct *ChoiceTable, p *Prog, c *Call) *state {
return s
}
-func newState(ct *ChoiceTable) *state {
+func newState(target *Target, ct *ChoiceTable) *state {
s := &state{
+ target: target,
ct: ct,
files: make(map[string]bool),
resources: make(map[string][]Arg),
@@ -66,7 +68,7 @@ func (s *state) analyze(c *Call) {
}
}
})
- start, npages, mapped := analyzeMmap(c)
+ start, npages, mapped := s.target.AnalyzeMmap(c)
if npages != 0 {
if start+npages > uint64(len(s.pages)) {
panic(fmt.Sprintf("address is out of bounds: page=%v len=%v bound=%v",
diff --git a/prog/checksum_test.go b/prog/checksum_test.go
index 004769328..d466cf2c2 100644
--- a/prog/checksum_test.go
+++ b/prog/checksum_test.go
@@ -11,9 +11,9 @@ import (
)
func TestChecksumCalcRandom(t *testing.T) {
- rs, iters := InitTest(t)
+ target, rs, iters := InitTest(t)
for i := 0; i < iters; i++ {
- p := Generate(rs, 10, nil)
+ p := target.Generate(rs, 10, nil)
for _, call := range p.Calls {
CalcChecksumsCall(call, i%32)
}
diff --git a/prog/clone.go b/prog/clone.go
index c0530949e..2253c7e75 100644
--- a/prog/clone.go
+++ b/prog/clone.go
@@ -9,7 +9,9 @@ func (p *Prog) Clone() *Prog {
}
func (p *Prog) cloneImpl(full bool) (*Prog, map[Arg]Arg) {
- p1 := new(Prog)
+ p1 := &Prog{
+ Target: p.Target,
+ }
newargs := make(map[Arg]Arg)
for _, c := range p.Calls {
c1 := new(Call)
diff --git a/prog/decl_test.go b/prog/decl_test.go
index e716cdf5e..51d5b0769 100644
--- a/prog/decl_test.go
+++ b/prog/decl_test.go
@@ -4,13 +4,18 @@
package prog
import (
+ "runtime"
"testing"
)
func TestResourceCtors(t *testing.T) {
- for _, c := range Syscalls {
- for _, res := range c.InputResources() {
- if len(calcResourceCtors(res.Desc.Kind, true)) == 0 {
+ target, err := GetTarget("linux", runtime.GOARCH)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, c := range target.Syscalls {
+ for _, res := range c.inputResources() {
+ if len(target.calcResourceCtors(res.Desc.Kind, true)) == 0 {
t.Errorf("call %v requires input resource %v, but there are no calls that can create this resource", c.Name, res.Desc.Name)
}
}
@@ -19,11 +24,15 @@ func TestResourceCtors(t *testing.T) {
func TestTransitivelyEnabledCalls(t *testing.T) {
t.Parallel()
+ target, err := GetTarget("linux", runtime.GOARCH)
+ if err != nil {
+ t.Fatal(err)
+ }
calls := make(map[*Syscall]bool)
- for _, c := range Syscalls {
+ for _, c := range target.Syscalls {
calls[c] = true
}
- if trans := TransitivelyEnabledCalls(calls); len(calls) != len(trans) {
+ if trans := target.TransitivelyEnabledCalls(calls); len(calls) != len(trans) {
for c := range calls {
if !trans[c] {
t.Logf("disabled %v", c.Name)
@@ -31,31 +40,35 @@ func TestTransitivelyEnabledCalls(t *testing.T) {
}
t.Fatalf("can't create some resource")
}
- delete(calls, SyscallMap["epoll_create"])
- if trans := TransitivelyEnabledCalls(calls); len(calls) != len(trans) {
+ delete(calls, target.SyscallMap["epoll_create"])
+ if trans := target.TransitivelyEnabledCalls(calls); len(calls) != len(trans) {
t.Fatalf("still must be able to create epoll fd with epoll_create1")
}
- delete(calls, SyscallMap["epoll_create1"])
- trans := TransitivelyEnabledCalls(calls)
+ delete(calls, target.SyscallMap["epoll_create1"])
+ trans := target.TransitivelyEnabledCalls(calls)
if len(calls)-5 != len(trans) ||
- trans[SyscallMap["epoll_ctl$EPOLL_CTL_ADD"]] ||
- trans[SyscallMap["epoll_ctl$EPOLL_CTL_MOD"]] ||
- trans[SyscallMap["epoll_ctl$EPOLL_CTL_DEL"]] ||
- trans[SyscallMap["epoll_wait"]] ||
- trans[SyscallMap["epoll_pwait"]] {
+ trans[target.SyscallMap["epoll_ctl$EPOLL_CTL_ADD"]] ||
+ trans[target.SyscallMap["epoll_ctl$EPOLL_CTL_MOD"]] ||
+ trans[target.SyscallMap["epoll_ctl$EPOLL_CTL_DEL"]] ||
+ trans[target.SyscallMap["epoll_wait"]] ||
+ trans[target.SyscallMap["epoll_pwait"]] {
t.Fatalf("epoll fd is not disabled")
}
}
func TestClockGettime(t *testing.T) {
t.Parallel()
+ target, err := GetTarget("linux", runtime.GOARCH)
+ if err != nil {
+ t.Fatal(err)
+ }
calls := make(map[*Syscall]bool)
- for _, c := range Syscalls {
+ for _, c := range target.Syscalls {
calls[c] = true
}
// Removal of clock_gettime should disable all calls that accept timespec/timeval.
- delete(calls, SyscallMap["clock_gettime"])
- trans := TransitivelyEnabledCalls(calls)
+ delete(calls, target.SyscallMap["clock_gettime"])
+ trans := target.TransitivelyEnabledCalls(calls)
if len(trans)+10 > len(calls) {
t.Fatalf("clock_gettime did not disable enough calls: before %v, after %v", len(calls), len(trans))
}
diff --git a/prog/encoding.go b/prog/encoding.go
index a6ded73ca..c140b89d6 100644
--- a/prog/encoding.go
+++ b/prog/encoding.go
@@ -121,8 +121,10 @@ func serialize(arg Arg, buf io.Writer, vars map[Arg]int, varSeq *int) {
}
}
-func Deserialize(data []byte) (prog *Prog, err error) {
- prog = new(Prog)
+func (target *Target) Deserialize(data []byte) (prog *Prog, err error) {
+ prog = &Prog{
+ Target: target,
+ }
p := &parser{r: bufio.NewScanner(bytes.NewReader(data))}
p.r.Buffer(nil, maxLineLen)
vars := make(map[string]Arg)
@@ -138,7 +140,7 @@ func Deserialize(data []byte) (prog *Prog, err error) {
name = p.Ident()
}
- meta := SyscallMap[name]
+ meta := target.SyscallMap[name]
if meta == nil {
return nil, fmt.Errorf("unknown syscall %v", name)
}
@@ -156,7 +158,7 @@ func Deserialize(data []byte) (prog *Prog, err error) {
if IsPad(typ) {
return nil, fmt.Errorf("padding in syscall %v arguments", name)
}
- arg, err := parseArg(typ, p, vars)
+ arg, err := target.parseArg(typ, p, vars)
if err != nil {
return nil, err
}
@@ -193,7 +195,7 @@ func Deserialize(data []byte) (prog *Prog, err error) {
return
}
-func parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, error) {
+func (target *Target) parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, error) {
r := ""
if p.Char() == '<' {
p.Parse('<')
@@ -261,7 +263,7 @@ func parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, error) {
return nil, err
}
p.Parse('=')
- inner, err := parseArg(typ1, p, vars)
+ inner, err := target.parseArg(typ1, p, vars)
if err != nil {
return nil, err
}
@@ -273,7 +275,7 @@ func parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, error) {
if err != nil {
return nil, err
}
- arg = MakeConstArg(typ, pages*pageSize)
+ arg = MakeConstArg(typ, pages*target.PageSize)
case '"':
p.Parse('"')
val := ""
@@ -301,7 +303,7 @@ func parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, error) {
if IsPad(fld) {
inner = append(inner, MakeConstArg(fld, 0))
} else {
- arg, err := parseArg(fld, p, vars)
+ arg, err := target.parseArg(fld, p, vars)
if err != nil {
return nil, err
}
@@ -324,7 +326,7 @@ func parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, error) {
p.Parse('[')
var inner []Arg
for i := 0; p.Char() != ']'; i++ {
- arg, err := parseArg(t1.Type, p, vars)
+ arg, err := target.parseArg(t1.Type, p, vars)
if err != nil {
return nil, err
}
@@ -353,7 +355,7 @@ func parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, error) {
if optType == nil {
return nil, fmt.Errorf("union arg %v has unknown option: %v", typ.Name(), name)
}
- opt, err := parseArg(optType, p, vars)
+ opt, err := target.parseArg(optType, p, vars)
if err != nil {
return nil, err
}
diff --git a/prog/encoding_test.go b/prog/encoding_test.go
index c58fe7dc8..8b7b84a2d 100644
--- a/prog/encoding_test.go
+++ b/prog/encoding_test.go
@@ -1,7 +1,7 @@
// Copyright 2016 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 prog_test
+package prog
import (
"fmt"
@@ -9,9 +9,6 @@ import (
"regexp"
"sort"
"testing"
-
- . "github.com/google/syzkaller/prog"
- _ "github.com/google/syzkaller/sys"
)
func setToArray(s map[string]struct{}) []string {
@@ -79,9 +76,9 @@ func TestCallSet(t *testing.T) {
}
func TestCallSetRandom(t *testing.T) {
- rs, iters := InitTest(t)
+ target, rs, iters := initTest(t)
for i := 0; i < iters; i++ {
- p := Generate(rs, 10, nil)
+ p := target.Generate(rs, 10, nil)
calls0 := make(map[string]struct{})
for _, c := range p.Calls {
calls0[c.Meta.Name] = struct{}{}
@@ -99,6 +96,7 @@ func TestCallSetRandom(t *testing.T) {
}
func TestDeserialize(t *testing.T) {
+ target, _, _ := initTest(t)
tests := []struct {
data string
err *regexp.Regexp
@@ -113,7 +111,7 @@ func TestDeserialize(t *testing.T) {
},
}
for _, test := range tests {
- _, err := Deserialize([]byte(test.data))
+ _, err := target.Deserialize([]byte(test.data))
if err != nil {
if test.err == nil {
t.Fatalf("deserialization failed with\n%s\ndata:\n%s\n", err, test.data)
diff --git a/prog/encodingexec.go b/prog/encodingexec.go
index a4f41a694..b2b173bbe 100644
--- a/prog/encodingexec.go
+++ b/prog/encodingexec.go
@@ -66,9 +66,10 @@ func (p *Prog) SerializeForExec(buffer []byte, pid int) error {
}
instrSeq := 0
w := &execContext{
- buf: buffer,
- eof: false,
- args: make(map[Arg]argInfo),
+ target: p.Target,
+ buf: buffer,
+ eof: false,
+ args: make(map[Arg]argInfo),
}
for _, c := range p.Calls {
// Calculate checksums.
@@ -94,7 +95,7 @@ func (p *Prog) SerializeForExec(buffer []byte, pid int) error {
foreachSubargOffset(a.Res, func(arg1 Arg, offset uint64) {
used, ok := arg1.(ArgUsed)
if (ok && len(*used.Used()) != 0) || csumUses[arg1] {
- w.args[arg1] = argInfo{Addr: physicalAddr(arg) + offset}
+ w.args[arg1] = argInfo{Addr: p.Target.physicalAddr(arg) + offset}
}
if _, ok := arg1.(*GroupArg); ok {
return
@@ -107,7 +108,7 @@ func (p *Prog) SerializeForExec(buffer []byte, pid int) error {
}
if !IsPad(arg1.Type()) && arg1.Type().Dir() != DirOut {
w.write(ExecInstrCopyin)
- w.write(physicalAddr(arg) + offset)
+ w.write(p.Target.physicalAddr(arg) + offset)
w.writeArg(arg1, pid, csumMap)
instrSeq++
}
@@ -197,24 +198,25 @@ func (p *Prog) SerializeForExec(buffer []byte, pid int) error {
return nil
}
-func physicalAddr(arg Arg) uint64 {
+func (target *Target) physicalAddr(arg Arg) uint64 {
a, ok := arg.(*PointerArg)
if !ok {
panic("physicalAddr: bad arg kind")
}
- addr := a.PageIndex*pageSize + dataOffset
+ addr := a.PageIndex*target.PageSize + target.DataOffset
if a.PageOffset >= 0 {
addr += uint64(a.PageOffset)
} else {
- addr += pageSize - uint64(-a.PageOffset)
+ addr += target.PageSize - uint64(-a.PageOffset)
}
return addr
}
type execContext struct {
- buf []byte
- eof bool
- args map[Arg]argInfo
+ target *Target
+ buf []byte
+ eof bool
+ args map[Arg]argInfo
}
type argInfo struct {
@@ -263,7 +265,7 @@ func (w *execContext) writeArg(arg Arg, pid int, csumMap map[Arg]CsumInfo) {
case *PointerArg:
w.write(ExecArgConst)
w.write(a.Size())
- w.write(physicalAddr(arg))
+ w.write(w.target.physicalAddr(arg))
w.write(0) // bit field offset
w.write(0) // bit field length
case *DataArg:
diff --git a/prog/encodingexec_test.go b/prog/encodingexec_test.go
index 9a2dd1d1e..3b37783f2 100644
--- a/prog/encodingexec_test.go
+++ b/prog/encodingexec_test.go
@@ -1,23 +1,20 @@
// Copyright 2016 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 prog_test
+package prog
import (
"bytes"
"encoding/binary"
"fmt"
"testing"
-
- . "github.com/google/syzkaller/prog"
- _ "github.com/google/syzkaller/sys"
)
func TestSerializeForExecRandom(t *testing.T) {
- rs, iters := InitTest(t)
+ target, rs, iters := initTest(t)
buf := make([]byte, ExecBufferSize)
for i := 0; i < iters; i++ {
- p := Generate(rs, 10, nil)
+ p := target.Generate(rs, 10, nil)
if err := p.SerializeForExec(buf, i%16); err != nil {
t.Fatalf("failed to serialize: %v", err)
}
@@ -45,12 +42,13 @@ func TestSerializeForExec(t *testing.T) {
argResult = uint64(ExecArgResult)
argData = uint64(ExecArgData)
)
+ target, _, _ := initTest(t)
var (
- dataOffset = DataOffset()
- ptrSize = PtrSize()
+ dataOffset = target.DataOffset
+ ptrSize = target.PtrSize
)
callID := func(name string) uint64 {
- c := SyscallMap[name]
+ c := target.SyscallMap[name]
if c == nil {
t.Fatalf("unknown syscall %v", name)
}
@@ -267,7 +265,7 @@ func TestSerializeForExec(t *testing.T) {
for i, test := range tests {
i, test := i, test
t.Run(fmt.Sprintf("%v:%v", i, test.prog), func(t *testing.T) {
- p, err := Deserialize([]byte(test.prog))
+ p, err := target.Deserialize([]byte(test.prog))
if err != nil {
t.Fatalf("failed to deserialize prog %v: %v", i, err)
}
diff --git a/prog/export_test.go b/prog/export_test.go
index c5337d695..e6c384c7a 100644
--- a/prog/export_test.go
+++ b/prog/export_test.go
@@ -17,11 +17,12 @@ func init() {
var (
CalcChecksumsCall = calcChecksumsCall
- AssignSizesCall = assignSizesCall
- DefaultArg = defaultArg
- InitTest = initTest
+ //AssignSizesCall = assignSizesCall
+ //DefaultArg = defaultArg
+ InitTest = initTest
)
+/*
func PtrSize() uint64 {
return ptrSize
}
@@ -33,8 +34,9 @@ func DataOffset() uint64 {
func PageSize() uint64 {
return pageSize
}
+*/
-func initTest(t *testing.T) (rand.Source, int) {
+func initTest(t *testing.T) (*Target, rand.Source, int) {
t.Parallel()
iters := 10000
if testing.Short() {
@@ -43,5 +45,9 @@ func initTest(t *testing.T) (rand.Source, int) {
seed := int64(time.Now().UnixNano())
rs := rand.NewSource(seed)
t.Logf("seed=%v", seed)
- return rs, iters
+ target, err := GetTarget("linux", "amd64")
+ if err != nil {
+ t.Fatal(err)
+ }
+ return target, rs, iters
}
diff --git a/prog/generation.go b/prog/generation.go
index 8ead1c1c5..860924031 100644
--- a/prog/generation.go
+++ b/prog/generation.go
@@ -9,10 +9,12 @@ import (
// Generate generates a random program of length ~ncalls.
// calls is a set of allowed syscalls, if nil all syscalls are used.
-func Generate(rs rand.Source, ncalls int, ct *ChoiceTable) *Prog {
- p := new(Prog)
- r := newRand(rs)
- s := newState(ct)
+func (target *Target) Generate(rs rand.Source, ncalls int, ct *ChoiceTable) *Prog {
+ p := &Prog{
+ Target: target,
+ }
+ r := newRand(target, rs)
+ s := newState(target, ct)
for len(p.Calls) < ncalls {
calls := r.generateCall(s, p)
for _, c := range calls {
diff --git a/prog/hints.go b/prog/hints.go
index b295b2151..1ba77fdd0 100644
--- a/prog/hints.go
+++ b/prog/hints.go
@@ -49,7 +49,7 @@ func (m CompMap) AddComp(arg1, arg2 uint64) {
// For each of the mutants executes the exec callback.
func (p *Prog) MutateWithHints(compMaps []CompMap, exec func(newP *Prog)) {
for i, c := range p.Calls {
- if c.Meta == defaultTarget.MmapSyscall {
+ if c.Meta == p.Target.MmapSyscall {
continue
}
foreachArg(c, func(arg, _ Arg, _ *[]Arg) {
diff --git a/prog/mutation.go b/prog/mutation.go
index d92c96361..ac6aa63fe 100644
--- a/prog/mutation.go
+++ b/prog/mutation.go
@@ -10,7 +10,7 @@ import (
)
func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Prog) {
- r := newRand(rs)
+ r := newRand(p.Target, rs)
retry := false
for stop := false; !stop || retry; stop = r.oneOf(3) {
@@ -55,13 +55,13 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Pro
continue
}
// Mutating mmap() arguments almost certainly doesn't give us new coverage.
- if c.Meta == defaultTarget.MmapSyscall && r.nOutOf(99, 100) {
+ if c.Meta == p.Target.MmapSyscall && r.nOutOf(99, 100) {
retry = true
continue
}
s := analyze(ct, p, c)
for stop := false; !stop; stop = r.oneOf(3) {
- args, bases := mutationArgs(c)
+ args, bases := p.Target.mutationArgs(c)
if len(args) == 0 {
retry = true
continue
@@ -152,9 +152,9 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Pro
}
}
for _, c1 := range calls {
- sanitizeCall(c1)
+ p.Target.SanitizeCall(c1)
}
- sanitizeCall(c)
+ p.Target.SanitizeCall(c)
p.insertBefore(c, calls)
} else if count < uint64(len(a.Inner)) {
for _, arg := range a.Inner[count:] {
@@ -176,7 +176,7 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Pro
arg1, calls1 := r.addr(s, t, size, a.Res)
p.replaceArg(c, arg, arg1, calls1)
case *StructType:
- gen := specialStructs[t.Name()]
+ gen := p.Target.SpecialStructs[t.Name()]
if gen == nil {
panic("bad arg returned by mutationArgs: StructType")
}
@@ -215,7 +215,7 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Pro
if baseSize < b.Res.Size() {
arg1, calls1 := r.addr(s, b.Type(), b.Res.Size(), b.Res)
for _, c1 := range calls1 {
- sanitizeCall(c1)
+ p.Target.SanitizeCall(c1)
}
p.insertBefore(c, calls1)
a1 := arg1.(*PointerArg)
@@ -226,7 +226,7 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Pro
}
// Update all len fields.
- assignSizesCall(c)
+ p.Target.assignSizesCall(c)
}
default:
// Remove a random call.
@@ -240,7 +240,7 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Pro
}
for _, c := range p.Calls {
- sanitizeCall(c)
+ p.Target.SanitizeCall(c)
}
if debug {
if err := p.validate(); err != nil {
@@ -289,7 +289,7 @@ func Minimize(p0 *Prog, callIndex0 int, pred0 func(*Prog, int) bool, crash bool)
// Remove all mmaps.
for i := 0; i < len(p.Calls); i++ {
c := p.Calls[i]
- if i != callIndex && c.Meta == defaultTarget.MmapSyscall {
+ if i != callIndex && c.Meta == p.Target.MmapSyscall {
p.removeCall(i)
if i < callIndex {
callIndex--
@@ -298,7 +298,7 @@ func Minimize(p0 *Prog, callIndex0 int, pred0 func(*Prog, int) bool, crash bool)
}
}
// Prepend uber-mmap.
- mmap := makeMmap(uint64(lo), uint64(hi-lo)+1)
+ mmap := p0.Target.MakeMmap(uint64(lo), uint64(hi-lo)+1)
p.Calls = append([]*Call{mmap}, p.Calls...)
if callIndex != -1 {
callIndex++
@@ -365,7 +365,7 @@ func Minimize(p0 *Prog, callIndex0 int, pred0 func(*Prog, int) bool, crash bool)
copy(a.Inner[i:], a.Inner[i+1:])
a.Inner = a.Inner[:len(a.Inner)-1]
p.removeArg(call, innerArg)
- assignSizesCall(call)
+ p.Target.assignSizesCall(call)
if pred(p, callIndex0) {
p0 = p
@@ -438,12 +438,12 @@ func Minimize(p0 *Prog, callIndex0 int, pred0 func(*Prog, int) bool, crash bool)
for step := len(a.Data) - minLen; len(a.Data) > minLen && step > 0; {
if len(a.Data)-step >= minLen {
a.Data = a.Data[:len(a.Data)-step]
- assignSizesCall(call)
+ p.Target.assignSizesCall(call)
if pred(p, callIndex0) {
continue
}
a.Data = a.Data[:len(a.Data)+step]
- assignSizesCall(call)
+ p.Target.assignSizesCall(call)
}
step /= 2
if crash {
@@ -499,11 +499,11 @@ func (p *Prog) TrimAfter(idx int) {
p.Calls = p.Calls[:idx+1]
}
-func mutationArgs(c *Call) (args, bases []Arg) {
+func (target *Target) mutationArgs(c *Call) (args, bases []Arg) {
foreachArg(c, func(arg, base Arg, _ *[]Arg) {
switch typ := arg.Type().(type) {
case *StructType:
- if specialStructs[typ.Name()] == nil {
+ if target.SpecialStructs[typ.Name()] == nil {
// For structs only individual fields are updated.
return
}
@@ -531,7 +531,8 @@ func mutationArgs(c *Call) (args, bases []Arg) {
return
}
if base != nil {
- if _, ok := base.Type().(*StructType); ok && specialStructs[base.Type().Name()] != nil {
+ if _, ok := base.Type().(*StructType); ok &&
+ target.SpecialStructs[base.Type().Name()] != nil {
// These special structs are mutated as a whole.
return
}
diff --git a/prog/mutation_test.go b/prog/mutation_test.go
index 060fe5f33..4e9bb626a 100644
--- a/prog/mutation_test.go
+++ b/prog/mutation_test.go
@@ -1,21 +1,18 @@
// Copyright 2015 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 prog_test
+package prog
import (
"bytes"
"fmt"
"testing"
-
- . "github.com/google/syzkaller/prog"
- _ "github.com/google/syzkaller/sys"
)
func TestClone(t *testing.T) {
- rs, iters := InitTest(t)
+ target, rs, iters := initTest(t)
for i := 0; i < iters; i++ {
- p := Generate(rs, 10, nil)
+ p := target.Generate(rs, 10, nil)
p1 := p.Clone()
data := p.Serialize()
data1 := p1.Serialize()
@@ -26,10 +23,10 @@ func TestClone(t *testing.T) {
}
func TestMutate(t *testing.T) {
- rs, iters := InitTest(t)
+ target, rs, iters := initTest(t)
next:
for i := 0; i < iters; i++ {
- p := Generate(rs, 10, nil)
+ p := target.Generate(rs, 10, nil)
data0 := p.Serialize()
p1 := p.Clone()
// There is a chance that mutation will produce the same program.
@@ -50,14 +47,14 @@ next:
}
func TestMutateCorpus(t *testing.T) {
- rs, iters := InitTest(t)
+ target, rs, iters := initTest(t)
var corpus []*Prog
for i := 0; i < 100; i++ {
- p := Generate(rs, 10, nil)
+ p := target.Generate(rs, 10, nil)
corpus = append(corpus, p)
}
for i := 0; i < iters; i++ {
- p1 := Generate(rs, 10, nil)
+ p1 := target.Generate(rs, 10, nil)
p1.Mutate(rs, 10, nil, corpus)
}
}
@@ -140,10 +137,10 @@ func TestMutateTable(t *testing.T) {
"readv(r0, &(0x7f0000000000)=[{&(0x7f0000001000)=\"00\", 0x1}, {&(0x7f0000002000)=\"00\", 0x2}, {&(0x7f0000000000)=\"00\", 0x3}], 0x3)\n",
},
}
- rs, _ := InitTest(t)
+ target, rs, _ := initTest(t)
nextTest:
for ti, test := range tests {
- p, err := Deserialize([]byte(test[0]))
+ p, err := target.Deserialize([]byte(test[0]))
if err != nil {
t.Fatalf("failed to deserialize original program %v: %v", ti, err)
}
@@ -272,8 +269,9 @@ func TestMinimize(t *testing.T) {
2,
},
}
+ target, _, _ := initTest(t)
for ti, test := range tests {
- p, err := Deserialize([]byte(test.orig))
+ p, err := target.Deserialize([]byte(test.orig))
if err != nil {
t.Fatalf("failed to deserialize original program #%v: %v", ti, err)
}
@@ -291,10 +289,10 @@ func TestMinimize(t *testing.T) {
}
func TestMinimizeRandom(t *testing.T) {
- rs, iters := InitTest(t)
+ target, rs, iters := initTest(t)
iters /= 10 // Long test.
for i := 0; i < iters; i++ {
- p := Generate(rs, 5, nil)
+ p := target.Generate(rs, 5, nil)
Minimize(p, len(p.Calls)-1, func(p1 *Prog, callIndex int) bool {
return false
}, true)
@@ -303,7 +301,7 @@ func TestMinimizeRandom(t *testing.T) {
}, true)
}
for i := 0; i < iters; i++ {
- p := Generate(rs, 5, nil)
+ p := target.Generate(rs, 5, nil)
Minimize(p, len(p.Calls)-1, func(p1 *Prog, callIndex int) bool {
return false
}, false)
diff --git a/prog/parse.go b/prog/parse.go
index 2044b1c9f..c62601702 100644
--- a/prog/parse.go
+++ b/prog/parse.go
@@ -19,7 +19,7 @@ type LogEntry struct {
FaultNth int
}
-func ParseLog(data []byte) []*LogEntry {
+func (target *Target) ParseLog(data []byte) []*LogEntry {
var entries []*LogEntry
ent := &LogEntry{}
var cur []byte
@@ -55,7 +55,7 @@ func ParseLog(data []byte) []*LogEntry {
continue
}
tmp := append(cur, line...)
- p, err := Deserialize(tmp)
+ p, err := target.Deserialize(tmp)
if err != nil {
continue
}
diff --git a/prog/parse_test.go b/prog/parse_test.go
index 2f5dd75d6..aae1e0a17 100644
--- a/prog/parse_test.go
+++ b/prog/parse_test.go
@@ -8,10 +8,14 @@ import (
)
func TestParseSingle(t *testing.T) {
+ target, err := GetTarget("linux", "amd64")
+ if err != nil {
+ t.Fatal(err)
+ }
const execLog = `getpid()
gettid()
`
- entries := ParseLog([]byte(execLog))
+ entries := target.ParseLog([]byte(execLog))
if len(entries) != 1 {
t.Fatalf("got %v programs, want 1", len(entries))
}
@@ -36,7 +40,11 @@ gettid()
}
func TestParseMulti(t *testing.T) {
- entries := ParseLog([]byte(execLog))
+ target, err := GetTarget("linux", "amd64")
+ if err != nil {
+ t.Fatal(err)
+ }
+ entries := target.ParseLog([]byte(execLog))
if len(entries) != 5 {
for i, ent := range entries {
t.Logf("program #%v: %s\n", i, ent.P)
@@ -99,11 +107,15 @@ munlockall()
`
func TestParseFault(t *testing.T) {
+ target, err := GetTarget("linux", "amd64")
+ if err != nil {
+ t.Fatal(err)
+ }
const execLog = `2015/12/21 12:18:05 executing program 1 (fault-call:1 fault-nth:55):
gettid()
getpid()
`
- entries := ParseLog([]byte(execLog))
+ entries := target.ParseLog([]byte(execLog))
if len(entries) != 1 {
t.Fatalf("got %v programs, want 1", len(entries))
}
diff --git a/prog/prio.go b/prog/prio.go
index e4a9b334f..110657d8d 100644
--- a/prog/prio.go
+++ b/prog/prio.go
@@ -24,9 +24,9 @@ import (
// Note: the current implementation is very basic, there is no theory behind any
// constants.
-func CalculatePriorities(corpus []*Prog) [][]float32 {
- static := calcStaticPriorities()
- dynamic := calcDynamicPrio(corpus)
+func (target *Target) CalculatePriorities(corpus []*Prog) [][]float32 {
+ static := target.calcStaticPriorities()
+ dynamic := target.calcDynamicPrio(corpus)
for i, prios := range static {
for j, p := range prios {
dynamic[i][j] *= p
@@ -35,9 +35,9 @@ func CalculatePriorities(corpus []*Prog) [][]float32 {
return dynamic
}
-func calcStaticPriorities() [][]float32 {
+func (target *Target) calcStaticPriorities() [][]float32 {
uses := make(map[string]map[int]float32)
- for _, c := range Syscalls {
+ for _, c := range target.Syscalls {
noteUsage := func(weight float32, str string, args ...interface{}) {
id := fmt.Sprintf(str, args...)
if uses[id] == nil {
@@ -99,9 +99,9 @@ func calcStaticPriorities() [][]float32 {
}
})
}
- prios := make([][]float32, len(Syscalls))
+ prios := make([][]float32, len(target.Syscalls))
for i := range prios {
- prios[i] = make([]float32, len(Syscalls))
+ prios[i] = make([]float32, len(target.Syscalls))
}
for _, calls := range uses {
for c0, w0 := range calls {
@@ -130,10 +130,10 @@ func calcStaticPriorities() [][]float32 {
return prios
}
-func calcDynamicPrio(corpus []*Prog) [][]float32 {
- prios := make([][]float32, len(Syscalls))
+func (target *Target) calcDynamicPrio(corpus []*Prog) [][]float32 {
+ prios := make([][]float32, len(target.Syscalls))
for i := range prios {
- prios[i] = make([]float32, len(Syscalls))
+ prios[i] = make([]float32, len(target.Syscalls))
}
for _, p := range corpus {
for _, c0 := range p.Calls {
@@ -141,8 +141,8 @@ func calcDynamicPrio(corpus []*Prog) [][]float32 {
id0 := c0.Meta.ID
id1 := c1.Meta.ID
// There are too many mmap's anyway.
- if id0 == id1 || c0.Meta == defaultTarget.MmapSyscall ||
- c1.Meta == defaultTarget.MmapSyscall {
+ if id0 == id1 || c0.Meta == target.MmapSyscall ||
+ c1.Meta == target.MmapSyscall {
continue
}
prios[id0][id1] += 1.0
@@ -194,15 +194,16 @@ func normalizePrio(prios [][]float32) {
// ChooseTable allows to do a weighted choice of a syscall for a given syscall
// based on call-to-call priorities and a set of enabled syscalls.
type ChoiceTable struct {
+ target *Target
run [][]int
enabledCalls []*Syscall
enabled map[*Syscall]bool
}
-func BuildChoiceTable(prios [][]float32, enabled map[*Syscall]bool) *ChoiceTable {
+func (target *Target) BuildChoiceTable(prios [][]float32, enabled map[*Syscall]bool) *ChoiceTable {
if enabled == nil {
enabled = make(map[*Syscall]bool)
- for _, c := range Syscalls {
+ for _, c := range target.Syscalls {
enabled[c] = true
}
}
@@ -210,27 +211,24 @@ func BuildChoiceTable(prios [][]float32, enabled map[*Syscall]bool) *ChoiceTable
for c := range enabled {
enabledCalls = append(enabledCalls, c)
}
- run := make([][]int, len(Syscalls))
+ run := make([][]int, len(target.Syscalls))
for i := range run {
- if !enabled[Syscalls[i]] {
+ if !enabled[target.Syscalls[i]] {
continue
}
- run[i] = make([]int, len(Syscalls))
+ run[i] = make([]int, len(target.Syscalls))
sum := 0
for j := range run[i] {
- if enabled[Syscalls[j]] {
+ if enabled[target.Syscalls[j]] {
sum += int(prios[i][j] * 1000)
}
run[i][j] = sum
}
}
- return &ChoiceTable{run, enabledCalls, enabled}
+ return &ChoiceTable{target, run, enabledCalls, enabled}
}
func (ct *ChoiceTable) Choose(r *rand.Rand, call int) int {
- if ct == nil {
- return r.Intn(len(Syscalls))
- }
if call < 0 {
return ct.enabledCalls[r.Intn(len(ct.enabledCalls))].ID
}
@@ -241,7 +239,7 @@ func (ct *ChoiceTable) Choose(r *rand.Rand, call int) int {
for {
x := r.Intn(run[len(run)-1])
i := sort.SearchInts(run, x)
- if !ct.enabled[Syscalls[i]] {
+ if !ct.enabled[ct.target.Syscalls[i]] {
continue
}
return i
diff --git a/prog/prog.go b/prog/prog.go
index 579bac4e0..744947895 100644
--- a/prog/prog.go
+++ b/prog/prog.go
@@ -8,7 +8,8 @@ import (
)
type Prog struct {
- Calls []*Call
+ Target *Target
+ Calls []*Call
}
type Call struct {
@@ -318,7 +319,7 @@ func (p *Prog) insertBefore(c *Call, calls []*Call) {
// replaceArg replaces arg with arg1 in call c in program p, and inserts calls before arg call.
func (p *Prog) replaceArg(c *Call, arg, arg1 Arg, calls []*Call) {
for _, c := range calls {
- sanitizeCall(c)
+ p.Target.SanitizeCall(c)
}
p.insertBefore(c, calls)
switch a := arg.(type) {
@@ -345,7 +346,7 @@ func (p *Prog) replaceArg(c *Call, arg, arg1 Arg, calls []*Call) {
default:
panic(fmt.Sprintf("replaceArg: bad arg kind %v", arg))
}
- sanitizeCall(c)
+ p.Target.SanitizeCall(c)
}
// removeArg removes all references to/from arg0 of call c from p.
diff --git a/prog/prog_test.go b/prog/prog_test.go
index 53ce959d6..e5ac2c927 100644
--- a/prog/prog_test.go
+++ b/prog/prog_test.go
@@ -10,27 +10,27 @@ import (
)
func TestGeneration(t *testing.T) {
- rs, iters := InitTest(t)
+ target, rs, iters := initTest(t)
for i := 0; i < iters; i++ {
- Generate(rs, 20, nil)
+ target.Generate(rs, 20, nil)
}
}
func TestDefault(t *testing.T) {
- InitTest(t)
- for _, meta := range SyscallMap {
+ target, _, _ := initTest(t)
+ for _, meta := range target.SyscallMap {
for _, t := range meta.Args {
- DefaultArg(t)
+ defaultArg(t)
}
}
}
func TestDefaultCallArgs(t *testing.T) {
- InitTest(t)
- for _, meta := range SyscallMap {
+ target, _, _ := initTest(t)
+ for _, meta := range target.SyscallMap {
// Ensure that we can restore all arguments of all calls.
prog := fmt.Sprintf("%v()", meta.Name)
- p, err := Deserialize([]byte(prog))
+ p, err := target.Deserialize([]byte(prog))
if err != nil {
t.Fatalf("failed to restore default args in prog %q: %v", prog, err)
}
@@ -41,11 +41,11 @@ func TestDefaultCallArgs(t *testing.T) {
}
func TestSerialize(t *testing.T) {
- rs, iters := InitTest(t)
+ target, rs, iters := initTest(t)
for i := 0; i < iters; i++ {
- p := Generate(rs, 10, nil)
+ p := target.Generate(rs, 10, nil)
data := p.Serialize()
- p1, err := Deserialize(data)
+ p1, err := target.Deserialize(data)
if err != nil {
t.Fatalf("failed to deserialize program: %v\n%s", err, data)
}
@@ -63,12 +63,12 @@ func TestSerialize(t *testing.T) {
}
func TestVmaType(t *testing.T) {
- rs, iters := InitTest(t)
- meta := SyscallMap["syz_test$vma0"]
- r := newRand(rs)
- pageSize := PageSize()
+ target, rs, iters := initTest(t)
+ meta := target.SyscallMap["syz_test$vma0"]
+ r := newRand(target, rs)
+ pageSize := target.PageSize
for i := 0; i < iters; i++ {
- s := newState(nil)
+ s := newState(target, nil)
calls := r.generateParticularCall(s, meta)
c := calls[len(calls)-1]
if c.Meta.Name != "syz_test$vma0" {
diff --git a/prog/rand.go b/prog/rand.go
index 8439015e7..aaab54610 100644
--- a/prog/rand.go
+++ b/prog/rand.go
@@ -18,12 +18,17 @@ var pageStartPool = sync.Pool{New: func() interface{} { return new([]uint64) }}
type randGen struct {
*rand.Rand
+ target *Target
inCreateResource bool
recDepth map[string]int
}
-func newRand(rs rand.Source) *randGen {
- return &randGen{rand.New(rs), false, make(map[string]int)}
+func newRand(target *Target, rs rand.Source) *randGen {
+ return &randGen{
+ Rand: rand.New(rs),
+ target: target,
+ recDepth: make(map[string]int),
+ }
}
func (r *randGen) rand(n int) uint64 {
@@ -205,8 +210,9 @@ func (r *randGen) randStringImpl(s *state, vals []string) []byte {
for r.nOutOf(3, 4) {
switch {
case r.nOutOf(10, 21):
- if len(stringDictionary) != 0 {
- buf.WriteString(stringDictionary[r.Intn(len(stringDictionary))])
+ dict := r.target.StringDictionary
+ if len(dict) != 0 {
+ buf.WriteString(dict[r.Intn(len(dict))])
}
case r.nOutOf(10, 11):
buf.Write([]byte{punct[r.Intn(len(punct))]})
@@ -221,7 +227,7 @@ func (r *randGen) randStringImpl(s *state, vals []string) []byte {
}
func (r *randGen) addr1(s *state, typ Type, size uint64, data Arg) (Arg, []*Call) {
- npages := (size + pageSize - 1) / pageSize
+ npages := (size + r.target.PageSize - 1) / r.target.PageSize
if npages == 0 {
npages = 1
}
@@ -239,7 +245,7 @@ func (r *randGen) addr1(s *state, typ Type, size uint64, data Arg) (Arg, []*Call
if !free {
continue
}
- c := makeMmap(i, npages)
+ c := r.target.MakeMmap(i, npages)
return MakePointerArg(typ, i, 0, 0, data), []*Call{c}
}
return r.randPageAddr(s, typ, npages, data, false), nil
@@ -257,7 +263,7 @@ func (r *randGen) addr(s *state, typ Type, size uint64, data Arg) (Arg, []*Call)
case r.nOutOf(50, 52):
a.PageOffset = -int(size)
case r.nOutOf(1, 2):
- a.PageOffset = r.Intn(int(pageSize))
+ a.PageOffset = r.Intn(int(r.target.PageSize))
default:
if size > 0 {
a.PageOffset = -r.Intn(int(size))
@@ -310,15 +316,15 @@ func (r *randGen) createResource(s *state, res *ResourceType) (arg Arg, calls []
if r.oneOf(1000) {
// Spoof resource subkind.
var all []string
- for kind1 := range Resources {
- if IsCompatibleResource(res.Desc.Kind[0], kind1) {
+ for kind1 := range r.target.resourceMap {
+ if r.target.isCompatibleResource(res.Desc.Kind[0], kind1) {
all = append(all, kind1)
}
}
kind = all[r.Intn(len(all))]
}
// Find calls that produce the necessary resources.
- metas0 := resourceCtors[kind]
+ metas0 := r.target.resourceCtors[kind]
// TODO: reduce priority of less specialized ctors.
var metas []*Syscall
for _, meta := range metas0 {
@@ -336,12 +342,12 @@ func (r *randGen) createResource(s *state, res *ResourceType) (arg Arg, calls []
// Generate one of them.
meta := metas[r.Intn(len(metas))]
calls := r.generateParticularCall(s, meta)
- s1 := newState(s.ct)
+ s1 := newState(r.target, s.ct)
s1.analyze(calls[len(calls)-1])
// Now see if we have what we want.
var allres []Arg
for kind1, res1 := range s1.resources {
- if IsCompatibleResource(kind, kind1) {
+ if r.target.isCompatibleResource(kind, kind1) {
allres = append(allres, res1...)
}
}
@@ -438,12 +444,19 @@ func (r *randGen) generateCall(s *state, p *Prog) []*Call {
c := p.Calls[r.Intn(len(p.Calls))].Meta
call = c.ID
// There is roughly half of mmap's so ignore them.
- if c != defaultTarget.MmapSyscall {
+ if c != r.target.MmapSyscall {
break
}
}
}
- meta := Syscalls[s.ct.Choose(r.Rand, call)]
+
+ idx := 0
+ if s.ct == nil {
+ idx = r.Intn(len(r.target.Syscalls))
+ } else {
+ idx = s.ct.Choose(r.Rand, call)
+ }
+ meta := r.target.Syscalls[idx]
return r.generateParticularCall(s, meta)
}
@@ -453,21 +466,23 @@ func (r *randGen) generateParticularCall(s *state, meta *Syscall) (calls []*Call
Ret: MakeReturnArg(meta.Ret),
}
c.Args, calls = r.generateArgs(s, meta.Args)
- assignSizesCall(c)
+ r.target.assignSizesCall(c)
calls = append(calls, c)
for _, c1 := range calls {
- sanitizeCall(c1)
+ r.target.SanitizeCall(c1)
}
return calls
}
// GenerateAllSyzProg generates a program that contains all pseudo syz_ calls for testing.
-func GenerateAllSyzProg(rs rand.Source) *Prog {
- p := new(Prog)
- r := newRand(rs)
- s := newState(nil)
+func (target *Target) GenerateAllSyzProg(rs rand.Source) *Prog {
+ p := &Prog{
+ Target: target,
+ }
+ r := newRand(target, rs)
+ s := newState(target, nil)
handled := make(map[string]bool)
- for _, meta := range Syscalls {
+ for _, meta := range target.Syscalls {
if !strings.HasPrefix(meta.CallName, "syz_") || handled[meta.CallName] {
continue
}
@@ -544,8 +559,8 @@ func (r *randGen) generateArg(s *state, typ Type) (arg Arg, calls []*Call) {
if name1 == "iocbptr" {
continue
}
- if IsCompatibleResource(a.Desc.Name, name1) ||
- r.oneOf(20) && IsCompatibleResource(a.Desc.Kind[0], name1) {
+ if r.target.isCompatibleResource(a.Desc.Name, name1) ||
+ r.oneOf(20) && r.target.isCompatibleResource(a.Desc.Kind[0], name1) {
allres = append(allres, res1...)
}
}
@@ -645,7 +660,7 @@ func (r *randGen) generateArg(s *state, typ Type) (arg Arg, calls []*Call) {
}
return MakeGroupArg(a, inner), calls
case *StructType:
- if gen := specialStructs[a.Name()]; gen != nil && a.Dir() != DirOut {
+ if gen := r.target.SpecialStructs[a.Name()]; gen != nil && a.Dir() != DirOut {
arg, calls = gen(&Gen{r, s}, a, nil)
return
}
diff --git a/prog/resources.go b/prog/resources.go
index 5fc6732ec..f7d124848 100644
--- a/prog/resources.go
+++ b/prog/resources.go
@@ -7,10 +7,10 @@ import (
"fmt"
)
-func calcResourceCtors(kind []string, precise bool) []*Syscall {
+func (target *Target) calcResourceCtors(kind []string, precise bool) []*Syscall {
// Find calls that produce the necessary resources.
var metas []*Syscall
- for _, meta := range Syscalls {
+ for _, meta := range target.Syscalls {
// Recurse into arguments to see if there is an out/inout arg of necessary type.
ok := false
ForeachType(meta, func(typ Type) {
@@ -19,7 +19,7 @@ func calcResourceCtors(kind []string, precise bool) []*Syscall {
}
switch typ1 := typ.(type) {
case *ResourceType:
- if typ1.Dir() != DirIn && isCompatibleResource(kind, typ1.Desc.Kind, precise) {
+ if typ1.Dir() != DirIn && isCompatibleResourceImpl(kind, typ1.Desc.Kind, precise) {
ok = true
}
}
@@ -31,23 +31,23 @@ func calcResourceCtors(kind []string, precise bool) []*Syscall {
return metas
}
-// IsCompatibleResource returns true if resource of kind src can be passed as an argument of kind dst.
-func IsCompatibleResource(dst, src string) bool {
- dstRes := Resources[dst]
+// isCompatibleResource returns true if resource of kind src can be passed as an argument of kind dst.
+func (target *Target) isCompatibleResource(dst, src string) bool {
+ dstRes := target.resourceMap[dst]
if dstRes == nil {
panic(fmt.Sprintf("unknown resource '%v'", dst))
}
- srcRes := Resources[src]
+ srcRes := target.resourceMap[src]
if srcRes == nil {
panic(fmt.Sprintf("unknown resource '%v'", src))
}
- return isCompatibleResource(dstRes.Kind, srcRes.Kind, false)
+ return isCompatibleResourceImpl(dstRes.Kind, srcRes.Kind, false)
}
-// isCompatibleResource returns true if resource of kind src can be passed as an argument of kind dst.
+// isCompatibleResourceImpl returns true if resource of kind src can be passed as an argument of kind dst.
// If precise is true, then it does not allow passing a less specialized resource (e.g. fd)
// as a more specialized resource (e.g. socket). Otherwise it does.
-func isCompatibleResource(dst, src []string, precise bool) bool {
+func isCompatibleResourceImpl(dst, src []string, precise bool) bool {
if len(dst) > len(src) {
// dst is more specialized, e.g dst=socket, src=fd.
if precise {
@@ -67,7 +67,7 @@ func isCompatibleResource(dst, src []string, precise bool) bool {
return true
}
-func (c *Syscall) InputResources() []*ResourceType {
+func (c *Syscall) inputResources() []*ResourceType {
var resources []*ResourceType
ForeachType(c, func(typ Type) {
switch typ1 := typ.(type) {
@@ -80,7 +80,7 @@ func (c *Syscall) InputResources() []*ResourceType {
return resources
}
-func TransitivelyEnabledCalls(enabled map[*Syscall]bool) map[*Syscall]bool {
+func (target *Target) TransitivelyEnabledCalls(enabled map[*Syscall]bool) map[*Syscall]bool {
supported := make(map[*Syscall]bool)
for c := range enabled {
supported[c] = true
@@ -88,18 +88,18 @@ func TransitivelyEnabledCalls(enabled map[*Syscall]bool) map[*Syscall]bool {
inputResources := make(map[*Syscall][]*ResourceType)
ctors := make(map[string][]*Syscall)
for c := range supported {
- inputs := c.InputResources()
+ inputs := c.inputResources()
inputResources[c] = inputs
for _, res := range inputs {
if _, ok := ctors[res.Desc.Name]; ok {
continue
}
- ctors[res.Desc.Name] = calcResourceCtors(res.Desc.Kind, true)
+ ctors[res.Desc.Name] = target.calcResourceCtors(res.Desc.Kind, true)
}
}
for {
n := len(supported)
- haveGettime := supported[SyscallMap["clock_gettime"]]
+ haveGettime := supported[target.SyscallMap["clock_gettime"]]
for c := range supported {
canCreate := true
for _, res := range inputResources[c] {
diff --git a/prog/size.go b/prog/size.go
index b9920c19b..538b60c5d 100644
--- a/prog/size.go
+++ b/prog/size.go
@@ -7,7 +7,7 @@ import (
"fmt"
)
-func generateSize(arg Arg, lenType *LenType) Arg {
+func (target *Target) generateSize(arg Arg, lenType *LenType) Arg {
if arg == nil {
// Arg is an optional pointer, set size to 0.
return MakeConstArg(lenType, 0)
@@ -16,7 +16,7 @@ func generateSize(arg Arg, lenType *LenType) Arg {
switch arg.Type().(type) {
case *VmaType:
a := arg.(*PointerArg)
- return MakeConstArg(lenType, a.PagesNum*pageSize)
+ return MakeConstArg(lenType, a.PagesNum*target.PageSize)
case *ArrayType:
a := arg.(*GroupArg)
if lenType.ByteSize != 0 {
@@ -33,7 +33,7 @@ func generateSize(arg Arg, lenType *LenType) Arg {
}
}
-func assignSizes(args []Arg, parentsMap map[Arg]Arg) {
+func (target *Target) assignSizes(args []Arg, parentsMap map[Arg]Arg) {
// Create a map from field names to args.
argsMap := make(map[string]Arg)
for _, arg := range args {
@@ -53,7 +53,7 @@ func assignSizes(args []Arg, parentsMap map[Arg]Arg) {
buf, ok := argsMap[typ.Buf]
if ok {
- *a = *generateSize(InnerArg(buf), typ).(*ConstArg)
+ *a = *target.generateSize(InnerArg(buf), typ).(*ConstArg)
continue
}
@@ -86,7 +86,7 @@ func assignSizes(args []Arg, parentsMap map[Arg]Arg) {
}
}
-func assignSizesArray(args []Arg) {
+func (target *Target) assignSizesArray(args []Arg) {
parentsMap := make(map[Arg]Arg)
foreachArgArray(&args, nil, func(arg, base Arg, _ *[]Arg) {
if _, ok := arg.Type().(*StructType); ok {
@@ -95,14 +95,14 @@ func assignSizesArray(args []Arg) {
}
}
})
- assignSizes(args, parentsMap)
+ target.assignSizes(args, parentsMap)
foreachArgArray(&args, nil, func(arg, base Arg, _ *[]Arg) {
if _, ok := arg.Type().(*StructType); ok {
- assignSizes(arg.(*GroupArg).Inner, parentsMap)
+ target.assignSizes(arg.(*GroupArg).Inner, parentsMap)
}
})
}
-func assignSizesCall(c *Call) {
- assignSizesArray(c.Args)
+func (target *Target) assignSizesCall(c *Call) {
+ target.assignSizesArray(c.Args)
}
diff --git a/prog/size_test.go b/prog/size_test.go
index a3cb9a302..f52a6ecce 100644
--- a/prog/size_test.go
+++ b/prog/size_test.go
@@ -1,29 +1,21 @@
// Copyright 2016 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 prog_test
+package prog
import (
"bytes"
- "runtime"
"strings"
"testing"
-
- . "github.com/google/syzkaller/prog"
- _ "github.com/google/syzkaller/sys"
)
-func init() {
- SetDefaultTarget("linux", runtime.GOARCH)
-}
-
func TestAssignSizeRandom(t *testing.T) {
- rs, iters := InitTest(t)
+ target, rs, iters := initTest(t)
for i := 0; i < iters; i++ {
- p := Generate(rs, 10, nil)
+ p := target.Generate(rs, 10, nil)
data0 := p.Serialize()
for _, call := range p.Calls {
- AssignSizesCall(call)
+ target.assignSizesCall(call)
}
if data1 := p.Serialize(); !bytes.Equal(data0, data1) {
t.Fatalf("different lens assigned, initial: %v, new: %v", data0, data1)
@@ -31,7 +23,7 @@ func TestAssignSizeRandom(t *testing.T) {
p.Mutate(rs, 10, nil, nil)
data0 = p.Serialize()
for _, call := range p.Calls {
- AssignSizesCall(call)
+ target.assignSizesCall(call)
}
if data1 := p.Serialize(); !bytes.Equal(data0, data1) {
t.Fatalf("different lens assigned, initial: %v, new: %v", data0, data1)
@@ -40,6 +32,7 @@ func TestAssignSizeRandom(t *testing.T) {
}
func TestAssignSize(t *testing.T) {
+ target, _, _ := initTest(t)
tests := []struct {
unsizedProg string
sizedProg string
@@ -131,12 +124,12 @@ func TestAssignSize(t *testing.T) {
}
for i, test := range tests {
- p, err := Deserialize([]byte(test.unsizedProg))
+ p, err := target.Deserialize([]byte(test.unsizedProg))
if err != nil {
t.Fatalf("failed to deserialize prog %v: %v", i, err)
}
for _, call := range p.Calls {
- AssignSizesCall(call)
+ target.assignSizesCall(call)
}
p1 := strings.TrimSpace(string(p.Serialize()))
if p1 != test.sizedProg {
diff --git a/prog/target.go b/prog/target.go
index b8e76919d..8436dc629 100644
--- a/prog/target.go
+++ b/prog/target.go
@@ -46,8 +46,9 @@ type Target struct {
// Used as fallback when string type does not have own dictionary.
StringDictionary []string
+ // Filled by prog package:
+ SyscallMap map[string]*Syscall
resourceMap map[string]*ResourceDesc
- syscallMap map[string]*Syscall
// Maps resource name to a list of calls that can create the resource.
resourceCtors map[string][]*Syscall
}
@@ -63,14 +64,7 @@ func RegisterTarget(target *Target) {
targets[key] = target
}
-func GetTarget(OS, arch string) *Target {
- return targets[OS+"/"+arch]
-}
-
-// SetDefaultTarget sets default target for prog package.
-// Majority of the code is not prepared for multiple targets,
-// so we use default target as a temporary measure.
-func SetDefaultTarget(OS, arch string) error {
+func GetTarget(OS, arch string) (*Target, error) {
key := OS + "/" + arch
target := targets[key]
if target == nil {
@@ -78,41 +72,22 @@ func SetDefaultTarget(OS, arch string) error {
for _, t := range targets {
supported = append(supported, fmt.Sprintf("%v/%v", t.OS, t.Arch))
}
- return fmt.Errorf("unknown target: %v (supported: %v)", key, supported)
- }
- if defaultTarget != nil {
- return fmt.Errorf("default target is already set")
+ return nil, fmt.Errorf("unknown target: %v (supported: %v)", key, supported)
}
- defaultTarget = target
-
- Syscalls = target.Syscalls
- SyscallMap = target.syscallMap
- Resources = target.resourceMap
- resourceCtors = target.resourceCtors
- ptrSize = target.PtrSize
- pageSize = target.PageSize
- dataOffset = target.DataOffset
-
- makeMmap = target.MakeMmap
- analyzeMmap = target.AnalyzeMmap
- sanitizeCall = target.SanitizeCall
- specialStructs = target.SpecialStructs
- stringDictionary = target.StringDictionary
-
- return nil
+ return target, nil
}
func initTarget(target *Target) {
- target.syscallMap = make(map[string]*Syscall)
+ target.SyscallMap = make(map[string]*Syscall)
for _, c := range target.Syscalls {
- target.syscallMap[c.Name] = c
+ target.SyscallMap[c.Name] = c
}
target.resourceMap = make(map[string]*ResourceDesc)
target.resourceCtors = make(map[string][]*Syscall)
for _, r := range target.Resources {
target.resourceMap[r.Name] = r
- target.resourceCtors[r.Name] = calcResourceCtors(r.Kind, false)
+ target.resourceCtors[r.Name] = target.calcResourceCtors(r.Kind, false)
}
}
@@ -128,22 +103,3 @@ func (g *Gen) NOutOf(n, outOf int) bool {
func (g *Gen) Alloc(ptrType Type, data Arg) (Arg, []*Call) {
return g.r.addr(g.s, ptrType, data.Size(), data)
}
-
-var (
- ptrSize uint64
- pageSize uint64
- dataOffset uint64
-
- defaultTarget *Target
-
- Syscalls []*Syscall
- SyscallMap map[string]*Syscall
- Resources map[string]*ResourceDesc
- resourceCtors map[string][]*Syscall
-
- makeMmap func(start, npages uint64) *Call
- analyzeMmap func(c *Call) (start, npages uint64, mapped bool)
- sanitizeCall func(c *Call)
- specialStructs map[string]func(g *Gen, typ *StructType, old *GroupArg) (Arg, []*Call)
- stringDictionary []string
-)
diff --git a/syz-fuzzer/fuzzer.go b/syz-fuzzer/fuzzer.go
index 25b84c85d..f41296c9b 100644
--- a/syz-fuzzer/fuzzer.go
+++ b/syz-fuzzer/fuzzer.go
@@ -61,6 +61,7 @@ type Candidate struct {
var (
manager *RpcClient
+ target *prog.Target
signalMu sync.RWMutex
corpusSignal map[uint32]struct{}
@@ -106,7 +107,9 @@ func main() {
}
Logf(0, "fuzzer started")
- if err := prog.SetDefaultTarget(runtime.GOOS, *flagArch); err != nil {
+ var err error
+ target, err = prog.GetTarget(runtime.GOOS, *flagArch)
+ if err != nil {
Fatalf("%v", err)
}
@@ -139,8 +142,8 @@ func main() {
if err := RpcCall(*flagManager, "Manager.Connect", a, r); err != nil {
panic(err)
}
- calls := buildCallList(r.EnabledCalls)
- ct := prog.BuildChoiceTable(r.Prios, calls)
+ calls := buildCallList(target, r.EnabledCalls)
+ ct := target.BuildChoiceTable(r.Prios, calls)
for _, inp := range r.Inputs {
addInput(inp)
}
@@ -148,7 +151,7 @@ func main() {
maxSignal[s] = struct{}{}
}
for _, candidate := range r.Candidates {
- p, err := prog.Deserialize(candidate.Prog)
+ p, err := target.Deserialize(candidate.Prog)
if err != nil {
panic(err)
}
@@ -207,10 +210,10 @@ func main() {
if err != nil {
panic(err)
}
- if _, ok := calls[prog.SyscallMap["syz_emit_ethernet"]]; ok {
+ if _, ok := calls[target.SyscallMap["syz_emit_ethernet"]]; ok {
config.Flags |= ipc.FlagEnableTun
}
- if _, ok := calls[prog.SyscallMap["syz_extract_tcp_res"]]; ok {
+ if _, ok := calls[target.SyscallMap["syz_extract_tcp_res"]]; ok {
config.Flags |= ipc.FlagEnableTun
}
if faultInjectionEnabled {
@@ -297,7 +300,7 @@ func main() {
if len(corpus) == 0 || i%100 == 0 {
// Generate a new prog.
corpusMu.RUnlock()
- p := prog.Generate(rnd, programLength, ct)
+ p := target.Generate(rnd, programLength, ct)
Logf(1, "#%v: generated: %s", i, p)
execute(pid, env, p, false, false, false, false, &statExecGen)
} else {
@@ -385,7 +388,7 @@ func main() {
addInput(inp)
}
for _, candidate := range r.Candidates {
- p, err := prog.Deserialize(candidate.Prog)
+ p, err := target.Deserialize(candidate.Prog)
if err != nil {
panic(err)
}
@@ -412,23 +415,23 @@ func main() {
}
}
-func buildCallList(enabledCalls string) map[*prog.Syscall]bool {
+func buildCallList(target *prog.Target, enabledCalls string) map[*prog.Syscall]bool {
calls := make(map[*prog.Syscall]bool)
if enabledCalls != "" {
for _, id := range strings.Split(enabledCalls, ",") {
n, err := strconv.ParseUint(id, 10, 64)
- if err != nil || n >= uint64(len(prog.Syscalls)) {
+ if err != nil || n >= uint64(len(target.Syscalls)) {
panic(fmt.Sprintf("invalid syscall in -calls flag: %v", id))
}
- calls[prog.Syscalls[n]] = true
+ calls[target.Syscalls[n]] = true
}
} else {
- for _, c := range prog.Syscalls {
+ for _, c := range target.Syscalls {
calls[c] = true
}
}
- if supp, err := host.DetectSupportedSyscalls(); err != nil {
+ if supp, err := host.DetectSupportedSyscalls(target); err != nil {
Logf(0, "failed to detect host supported syscalls: %v", err)
} else {
for c := range calls {
@@ -439,7 +442,7 @@ func buildCallList(enabledCalls string) map[*prog.Syscall]bool {
}
}
- trans := prog.TransitivelyEnabledCalls(calls)
+ trans := target.TransitivelyEnabledCalls(calls)
for c := range calls {
if !trans[c] {
Logf(1, "disabling transitively unsupported syscall: %v", c.Name)
@@ -458,7 +461,7 @@ func addInput(inp RpcInput) {
if noCover {
panic("should not be called when coverage is disabled")
}
- p, err := prog.Deserialize(inp.Prog)
+ p, err := target.Deserialize(inp.Prog)
if err != nil {
panic(err)
}
diff --git a/syz-manager/html.go b/syz-manager/html.go
index a9a9b641a..77d39d6f4 100644
--- a/syz-manager/html.go
+++ b/syz-manager/html.go
@@ -23,7 +23,6 @@ import (
. "github.com/google/syzkaller/pkg/log"
"github.com/google/syzkaller/pkg/osutil"
"github.com/google/syzkaller/pkg/report"
- "github.com/google/syzkaller/prog"
)
const dateFormat = "Jan 02 2006 15:04:05 MST"
@@ -145,7 +144,7 @@ func (mgr *Manager) httpCorpus(w http.ResponseWriter, r *http.Request) {
if call != inp.Call {
continue
}
- p, err := prog.Deserialize(inp.Prog)
+ p, err := mgr.target.Deserialize(inp.Prog)
if err != nil {
http.Error(w, fmt.Sprintf("failed to deserialize program: %v", err), http.StatusInternalServerError)
return
@@ -195,7 +194,7 @@ func (mgr *Manager) httpPrio(w http.ResponseWriter, r *http.Request) {
mgr.minimizeCorpus()
call := r.FormValue("call")
idx := -1
- for i, c := range prog.Syscalls {
+ for i, c := range mgr.target.Syscalls {
if c.CallName == call {
idx = i
break
@@ -208,7 +207,7 @@ func (mgr *Manager) httpPrio(w http.ResponseWriter, r *http.Request) {
data := &UIPrioData{Call: call}
for i, p := range mgr.prios[idx] {
- data.Prios = append(data.Prios, UIPrio{prog.Syscalls[i].Name, p})
+ data.Prios = append(data.Prios, UIPrio{mgr.target.Syscalls[i].Name, p})
}
sort.Sort(UIPrioArray(data.Prios))
diff --git a/syz-manager/manager.go b/syz-manager/manager.go
index a7216b709..368ca2e8f 100644
--- a/syz-manager/manager.go
+++ b/syz-manager/manager.go
@@ -43,6 +43,7 @@ var (
type Manager struct {
cfg *mgrconfig.Config
vmPool *vm.Pool
+ target *prog.Target
crashdir string
port int
corpusDB *db.DB
@@ -114,7 +115,8 @@ func main() {
if err != nil {
Fatalf("%v", err)
}
- if err := prog.SetDefaultTarget(cfg.TargetOS, cfg.TargetArch); err != nil {
+ target, err := prog.GetTarget(cfg.TargetOS, cfg.TargetArch)
+ if err != nil {
Fatalf("%v", err)
}
syscalls, err := mgrconfig.ParseEnabledSyscalls(cfg)
@@ -122,12 +124,12 @@ func main() {
Fatalf("%v", err)
}
// mmap is used to allocate memory.
- syscalls[prog.GetTarget(cfg.TargetOS, cfg.TargetArch).MmapSyscall.ID] = true
+ syscalls[target.MmapSyscall.ID] = true
initAllCover(cfg.Vmlinux)
- RunManager(cfg, syscalls)
+ RunManager(cfg, target, syscalls)
}
-func RunManager(cfg *mgrconfig.Config, syscalls map[int]bool) {
+func RunManager(cfg *mgrconfig.Config, target *prog.Target, syscalls map[int]bool) {
env := mgrconfig.CreateVMEnv(cfg, *flagDebug)
vmPool, err := vm.Create(cfg.Type, env)
if err != nil {
@@ -150,6 +152,7 @@ func RunManager(cfg *mgrconfig.Config, syscalls map[int]bool) {
mgr := &Manager{
cfg: cfg,
vmPool: vmPool,
+ target: target,
crashdir: crashdir,
startTime: time.Now(),
stats: make(map[string]uint64),
@@ -174,7 +177,7 @@ func RunManager(cfg *mgrconfig.Config, syscalls map[int]bool) {
}
deleted := 0
for key, rec := range mgr.corpusDB.Records {
- p, err := prog.Deserialize(rec.Val)
+ p, err := mgr.target.Deserialize(rec.Val)
if err != nil {
if deleted < 10 {
Logf(0, "deleting broken program: %v\n%s", err, rec.Val)
@@ -814,13 +817,13 @@ func (mgr *Manager) Connect(a *ConnectArgs, r *ConnectRes) error {
corpus := make([]*prog.Prog, 0, len(inputs))
for _, inp := range inputs {
- p, err := prog.Deserialize(inp)
+ p, err := mgr.target.Deserialize(inp)
if err != nil {
panic(err)
}
corpus = append(corpus, p)
}
- prios := prog.CalculatePriorities(corpus)
+ prios := mgr.target.CalculatePriorities(corpus)
mgr.mu.Lock()
mgr.prios = prios
@@ -1067,7 +1070,7 @@ func (mgr *Manager) hubSync() {
reproDropped := 0
for _, repro := range r.Repros {
- _, err := prog.Deserialize(repro)
+ _, err := mgr.target.Deserialize(repro)
if err != nil {
reproDropped++
continue
@@ -1085,7 +1088,7 @@ func (mgr *Manager) hubSync() {
mgr.newRepros = nil
dropped := 0
for _, inp := range r.Progs {
- _, err := prog.Deserialize(inp)
+ _, err := mgr.target.Deserialize(inp)
if err != nil {
dropped++
continue
diff --git a/syz-manager/mgrconfig/mgrconfig.go b/syz-manager/mgrconfig/mgrconfig.go
index 1f9819154..8434db8a3 100644
--- a/syz-manager/mgrconfig/mgrconfig.go
+++ b/syz-manager/mgrconfig/mgrconfig.go
@@ -175,11 +175,16 @@ func ParseEnabledSyscalls(cfg *Config) (map[int]bool, error) {
return false
}
+ target, err := prog.GetTarget(cfg.TargetOS, cfg.TargetArch)
+ if err != nil {
+ return nil, err
+ }
+
syscalls := make(map[int]bool)
if len(cfg.Enable_Syscalls) != 0 {
for _, c := range cfg.Enable_Syscalls {
n := 0
- for _, call := range prog.Syscalls {
+ for _, call := range target.Syscalls {
if match(call, c) {
syscalls[call.ID] = true
n++
@@ -190,13 +195,13 @@ func ParseEnabledSyscalls(cfg *Config) (map[int]bool, error) {
}
}
} else {
- for _, call := range prog.Syscalls {
+ for _, call := range target.Syscalls {
syscalls[call.ID] = true
}
}
for _, c := range cfg.Disable_Syscalls {
n := 0
- for _, call := range prog.Syscalls {
+ for _, call := range target.Syscalls {
if match(call, c) {
delete(syscalls, call.ID)
n++
diff --git a/tools/syz-crush/crush.go b/tools/syz-crush/crush.go
index 059852200..6deeeffd8 100644
--- a/tools/syz-crush/crush.go
+++ b/tools/syz-crush/crush.go
@@ -37,7 +37,7 @@ func main() {
if len(flag.Args()) != 1 {
Fatalf("usage: syz-crush -config=config.file execution.log")
}
- if err := prog.SetDefaultTarget(cfg.TargetOS, cfg.TargetArch); err != nil {
+ if _, err := prog.GetTarget(cfg.TargetOS, cfg.TargetArch); err != nil {
Fatalf("%v", err)
}
env := mgrconfig.CreateVMEnv(cfg, false)
diff --git a/tools/syz-execprog/execprog.go b/tools/syz-execprog/execprog.go
index 53fcbb8ca..282e416e3 100644
--- a/tools/syz-execprog/execprog.go
+++ b/tools/syz-execprog/execprog.go
@@ -47,7 +47,8 @@ func main() {
os.Exit(1)
}
- if err := prog.SetDefaultTarget(runtime.GOOS, *flagArch); err != nil {
+ target, err := prog.GetTarget(runtime.GOOS, *flagArch)
+ if err != nil {
Fatalf("%v", err)
}
@@ -57,7 +58,7 @@ func main() {
if err != nil {
Fatalf("failed to read log file: %v", err)
}
- entries := prog.ParseLog(data)
+ entries := target.ParseLog(data)
for _, ent := range entries {
progs = append(progs, ent.P)
}
diff --git a/tools/syz-mutate/mutate.go b/tools/syz-mutate/mutate.go
index 1c15eabc5..242175ef8 100644
--- a/tools/syz-mutate/mutate.go
+++ b/tools/syz-mutate/mutate.go
@@ -27,7 +27,8 @@ func main() {
fmt.Fprintf(os.Stderr, "usage: mutate program\n")
os.Exit(1)
}
- if err := prog.SetDefaultTarget(runtime.GOOS, runtime.GOARCH); err != nil {
+ target, err := prog.GetTarget(runtime.GOOS, runtime.GOARCH)
+ if err != nil {
fmt.Fprintf(os.Stderr, "%v", err)
os.Exit(1)
}
@@ -36,14 +37,14 @@ func main() {
fmt.Fprintf(os.Stderr, "failed to read prog file: %v\n", err)
os.Exit(1)
}
- p, err := prog.Deserialize(data)
+ p, err := target.Deserialize(data)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to deserialize the program: %v\n", err)
os.Exit(1)
}
- prios := prog.CalculatePriorities(nil)
- ct := prog.BuildChoiceTable(prios, nil)
+ prios := target.CalculatePriorities(nil)
+ ct := target.BuildChoiceTable(prios, nil)
seed := time.Now().UnixNano()
if *flagSeed != -1 {
diff --git a/tools/syz-prog2c/prog2c.go b/tools/syz-prog2c/prog2c.go
index bc6453875..f0ab63f36 100644
--- a/tools/syz-prog2c/prog2c.go
+++ b/tools/syz-prog2c/prog2c.go
@@ -15,6 +15,7 @@ import (
)
var (
+ flagArch = flag.String("arch", runtime.GOARCH, "target arch")
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")
@@ -36,7 +37,8 @@ func main() {
flag.PrintDefaults()
os.Exit(1)
}
- if err := prog.SetDefaultTarget(runtime.GOOS, runtime.GOARCH); err != nil {
+ target, err := prog.GetTarget(runtime.GOOS, *flagArch)
+ if err != nil {
fmt.Fprintf(os.Stderr, "%v", err)
os.Exit(1)
}
@@ -45,7 +47,7 @@ func main() {
fmt.Fprintf(os.Stderr, "failed to read prog file: %v\n", err)
os.Exit(1)
}
- p, err := prog.Deserialize(data)
+ p, err := target.Deserialize(data)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to deserialize the program: %v\n", err)
os.Exit(1)
diff --git a/tools/syz-repro/repro.go b/tools/syz-repro/repro.go
index 310ea54a9..6d8316866 100644
--- a/tools/syz-repro/repro.go
+++ b/tools/syz-repro/repro.go
@@ -38,7 +38,7 @@ func main() {
if err != nil {
Fatalf("failed to open log file: %v", err)
}
- if err := prog.SetDefaultTarget(cfg.TargetOS, cfg.TargetArch); err != nil {
+ if _, err := prog.GetTarget(cfg.TargetOS, cfg.TargetArch); err != nil {
Fatalf("%v", err)
}
env := mgrconfig.CreateVMEnv(cfg, false)
diff --git a/tools/syz-stress/stress.go b/tools/syz-stress/stress.go
index 6e24f3915..77be42299 100644
--- a/tools/syz-stress/stress.go
+++ b/tools/syz-stress/stress.go
@@ -37,18 +37,19 @@ const programLength = 30
func main() {
flag.Parse()
- if err := prog.SetDefaultTarget(runtime.GOOS, runtime.GOARCH); err != nil {
+ target, err := prog.GetTarget(runtime.GOOS, runtime.GOARCH)
+ if err != nil {
Fatalf("%v", err)
}
- corpus := readCorpus()
+ corpus := readCorpus(target)
Logf(0, "parsed %v programs", len(corpus))
if !*flagGenerate && len(corpus) == 0 {
Fatalf("nothing to mutate (-generate=false and no corpus)")
}
- calls := buildCallList()
- prios := prog.CalculatePriorities(corpus)
- ct := prog.BuildChoiceTable(prios, calls)
+ calls := buildCallList(target)
+ prios := target.CalculatePriorities(corpus)
+ ct := target.BuildChoiceTable(prios, calls)
config, err := ipc.DefaultConfig()
if err != nil {
@@ -67,7 +68,7 @@ func main() {
for i := 0; ; i++ {
var p *prog.Prog
if *flagGenerate && len(corpus) == 0 || i%4 != 0 {
- p = prog.Generate(rs, programLength, ct)
+ p = target.Generate(rs, programLength, ct)
execute(pid, env, p)
p.Mutate(rs, programLength, ct, corpus)
execute(pid, env, p)
@@ -113,7 +114,7 @@ func execute(pid int, env *ipc.Env, p *prog.Prog) {
}
}
-func readCorpus() []*prog.Prog {
+func readCorpus(target *prog.Target) []*prog.Prog {
if *flagCorpus == "" {
return nil
}
@@ -123,7 +124,7 @@ func readCorpus() []*prog.Prog {
}
var progs []*prog.Prog
for _, rec := range db.Records {
- p, err := prog.Deserialize(rec.Val)
+ p, err := target.Deserialize(rec.Val)
if err != nil {
Fatalf("failed to deserialize corpus program: %v", err)
}
@@ -132,21 +133,21 @@ func readCorpus() []*prog.Prog {
return progs
}
-func buildCallList() map[*prog.Syscall]bool {
- calls, err := host.DetectSupportedSyscalls()
+func buildCallList(target *prog.Target) map[*prog.Syscall]bool {
+ calls, err := host.DetectSupportedSyscalls(target)
if err != nil {
Logf(0, "failed to detect host supported syscalls: %v", err)
calls = make(map[*prog.Syscall]bool)
- for _, c := range prog.Syscalls {
+ for _, c := range target.Syscalls {
calls[c] = true
}
}
- for _, c := range prog.Syscalls {
+ for _, c := range target.Syscalls {
if !calls[c] {
Logf(0, "disabling unsupported syscall: %v", c.Name)
}
}
- trans := prog.TransitivelyEnabledCalls(calls)
+ trans := target.TransitivelyEnabledCalls(calls)
for c := range calls {
if !trans[c] {
Logf(0, "disabling transitively unsupported syscall: %v", c.Name)
diff --git a/tools/syz-upgrade/upgrade.go b/tools/syz-upgrade/upgrade.go
index 0a28a27fb..d833fdc21 100644
--- a/tools/syz-upgrade/upgrade.go
+++ b/tools/syz-upgrade/upgrade.go
@@ -15,6 +15,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
+ "runtime"
"github.com/google/syzkaller/pkg/osutil"
"github.com/google/syzkaller/prog"
@@ -29,13 +30,17 @@ func main() {
if err != nil {
fatalf("failed to read corpus dir: %v", err)
}
+ target, err := prog.GetTarget(runtime.GOOS, runtime.GOARCH)
+ if err != nil {
+ fatalf("%v", err)
+ }
for _, f := range files {
fname := filepath.Join(os.Args[1], f.Name())
data, err := ioutil.ReadFile(fname)
if err != nil {
fatalf("failed to read program: %v", err)
}
- p, err := prog.Deserialize(data)
+ p, err := target.Deserialize(data)
if err != nil {
fatalf("failed to deserialize program: %v", err)
}