diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2017-09-14 19:25:01 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2017-09-15 16:02:37 +0200 |
| commit | 52a33fd516102a98d3753bf69417235b655a68dc (patch) | |
| tree | 351ab73db934d3b4e4babbe27e8801c659f2631b | |
| parent | 25f4fe0662f7f3b390d16b2e786f2ba0aa0293f1 (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.
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) } |
