| // Copyright 2021 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 main |
| |
| import ( |
| "flag" |
| "fmt" |
| "log" |
| "runtime" |
| |
| "github.com/google/syzkaller/pkg/host" |
| "github.com/google/syzkaller/pkg/ipc" |
| "github.com/google/syzkaller/pkg/ipc/ipcconfig" |
| "github.com/google/syzkaller/pkg/rpctype" |
| "github.com/google/syzkaller/prog" |
| ) |
| |
| // Runner is responsible of running programs sent by the host via RPC and |
| // reporting the execution results back to the host. |
| type Runner struct { |
| vrf *rpctype.RPCClient |
| target *prog.Target |
| opts *ipc.ExecOpts |
| config *ipc.Config |
| pool, vm int |
| newEnv bool |
| } |
| |
| func main() { |
| flagPool := flag.Int("pool", 0, "index of pool it corresponds to") |
| flagVM := flag.Int("vm", 0, "index of VM that started the Runner") |
| flagAddr := flag.String("addr", "", "verifier rpc address") |
| flagOS := flag.String("os", runtime.GOOS, "target OS") |
| flagArch := flag.String("arch", runtime.GOARCH, "target arch") |
| flagEnv := flag.Bool("new-env", true, "create a new environment for each program") |
| flag.Parse() |
| |
| target, err := prog.GetTarget(*flagOS, *flagArch) |
| if err != nil { |
| log.Fatalf("failed to configure target: %v", err) |
| } |
| |
| config, opts, err := ipcconfig.Default(target) |
| if err != nil { |
| log.Fatalf("failed to create default ipc config: %v", err) |
| } |
| |
| timeouts := config.Timeouts |
| vrf, err := rpctype.NewRPCClient(*flagAddr, timeouts.Scale) |
| if err != nil { |
| log.Fatalf("failed to connect to verifier : %v", err) |
| } |
| |
| rn := &Runner{ |
| vrf: vrf, |
| target: target, |
| opts: opts, |
| config: config, |
| pool: *flagPool, |
| vm: *flagVM, |
| newEnv: *flagEnv, |
| } |
| |
| a := &rpctype.RunnerConnectArgs{ |
| Pool: rn.pool, |
| VM: rn.vm, |
| } |
| r := &rpctype.RunnerConnectRes{} |
| if err := vrf.Call("Verifier.Connect", a, r); err != nil { |
| log.Fatalf("failed to connect to verifier: %v", err) |
| } |
| |
| enabled := make(map[*prog.Syscall]bool) |
| for _, c := range target.Syscalls { |
| enabled[c] = true |
| } |
| if r.CheckUnsupportedCalls { |
| _, unsupported, err := host.DetectSupportedSyscalls(target, ipc.FlagsToSandbox(config.Flags), enabled) |
| if err != nil { |
| log.Fatalf("failed to get unsupported system calls: %v", err) |
| } |
| |
| calls := make([]rpctype.SyscallReason, 0) |
| for c, reason := range unsupported { |
| calls = append(calls, rpctype.SyscallReason{ |
| ID: c.ID, |
| Reason: fmt.Sprintf("%s (not supported on kernel %d)", reason, rn.pool)}) |
| } |
| a := &rpctype.UpdateUnsupportedArgs{Pool: rn.pool, UnsupportedCalls: calls} |
| if err := vrf.Call("Verifier.UpdateUnsupported", a, nil); err != nil { |
| log.Fatalf("failed to send unsupported system calls: %v", err) |
| } |
| } |
| |
| res := &rpctype.NextExchangeRes{} |
| if err := rn.vrf.Call("Verifier.NextExchange", &rpctype.NextExchangeArgs{Pool: rn.pool, VM: rn.vm}, res); err != nil { |
| log.Fatalf("failed to get initial program: %v", err) |
| } |
| |
| rn.Run(res.Prog, res.ID) |
| } |
| |
| // Run is responsible for requesting new programs from the verifier, executing them and then sending back the Result. |
| // TODO: Implement functionality to execute several programs at once and send back a slice of results. |
| func (rn *Runner) Run(firstProg []byte, taskID int64) { |
| p, id := firstProg, taskID |
| |
| env, err := ipc.MakeEnv(rn.config, 0) |
| if err != nil { |
| log.Fatalf("failed to create initial execution environment: %v", err) |
| } |
| |
| for { |
| prog, err := rn.target.Deserialize(p, prog.NonStrict) |
| if err != nil { |
| log.Fatalf("failed to deserialise new program: %v", err) |
| } |
| |
| log.Printf("executing program") // watchdog for monitor |
| _, info, hanged, err := env.Exec(rn.opts, prog) |
| if err != nil { |
| log.Fatalf("failed to execute the program: %v", err) |
| } |
| |
| a := &rpctype.NextExchangeArgs{ |
| Pool: rn.pool, |
| VM: rn.vm, |
| Hanged: hanged, |
| Info: *info, |
| ExecTaskID: id, |
| } |
| |
| r := &rpctype.NextExchangeRes{} |
| if err := rn.vrf.Call("Verifier.NextExchange", a, r); err != nil { |
| log.Fatalf("failed to make exchange with verifier: %v", err) |
| } |
| p, id = r.Prog, r.ID |
| |
| if !rn.newEnv { |
| continue |
| } |
| |
| err = env.Close() |
| if err != nil { |
| log.Fatalf("failed to close the execution environment: %v", err) |
| } |
| |
| env, err = ipc.MakeEnv(rn.config, 0) |
| if err != nil { |
| log.Fatalf("failed to create new execution environmentL %v", err) |
| } |
| } |
| } |