diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2016-01-11 17:33:44 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2016-01-11 17:33:44 +0100 |
| commit | de48f7b019027f72dc84f56e9e5f0cb03645294e (patch) | |
| tree | 373842f113b5bc3fbefde37444e375a19dca8dcf | |
| parent | 46fa57f3b44ccbecfb20067778dae9a7f5a111a5 (diff) | |
vm: refactor VM interface in preparation for adb support
adb has more complex port forwarding setup, also / is mounted read-only.
Make VM interface more flexible to support such cases.
| -rw-r--r-- | config/config.go | 25 | ||||
| -rw-r--r-- | syz-manager/manager.go | 16 | ||||
| -rw-r--r-- | tools/syz-repro/repro.go | 32 | ||||
| -rw-r--r-- | vm/kvm/kvm.go | 22 | ||||
| -rw-r--r-- | vm/local/local.go | 29 | ||||
| -rw-r--r-- | vm/qemu/qemu.go | 24 | ||||
| -rw-r--r-- | vm/vm.go | 35 |
7 files changed, 110 insertions, 73 deletions
diff --git a/config/config.go b/config/config.go index 6ae3baa36..cb1c8a609 100644 --- a/config/config.go +++ b/config/config.go @@ -41,6 +41,8 @@ type Config struct { NoDropPrivs bool Leak bool // do memory leak checking + ConsoleDev string // console device for adb vm + Enable_Syscalls []string Disable_Syscalls []string Suppressions []string @@ -188,17 +190,18 @@ func CreateVMConfig(cfg *Config) (*vm.Config, error) { return nil, fmt.Errorf("failed to create instance temp dir: %v", err) } vmCfg := &vm.Config{ - Name: fmt.Sprintf("%v-%v", cfg.Type, index), - Index: index, - Workdir: workdir, - Bin: cfg.Bin, - Kernel: cfg.Kernel, - Cmdline: cfg.Cmdline, - Image: cfg.Image, - Sshkey: cfg.Sshkey, - Cpu: cfg.Cpu, - Mem: cfg.Mem, - Debug: cfg.Debug, + Name: fmt.Sprintf("%v-%v", cfg.Type, index), + Index: index, + Workdir: workdir, + Bin: cfg.Bin, + Kernel: cfg.Kernel, + Cmdline: cfg.Cmdline, + Image: cfg.Image, + Sshkey: cfg.Sshkey, + ConsoleDev: cfg.ConsoleDev, + Cpu: cfg.Cpu, + Mem: cfg.Mem, + Debug: cfg.Debug, } return vmCfg, nil } diff --git a/syz-manager/manager.go b/syz-manager/manager.go index b204edadd..2bebe8d6e 100644 --- a/syz-manager/manager.go +++ b/syz-manager/manager.go @@ -170,11 +170,18 @@ func (mgr *Manager) runInstance(vmCfg *vm.Config, first bool) bool { } defer inst.Close() - if err := inst.Copy(filepath.Join(mgr.cfg.Syzkaller, "bin/syz-fuzzer"), "/syz-fuzzer"); err != nil { + fwdAddr, err := inst.Forward(mgr.port) + if err != nil { + logf(0, "failed to setup port forwarding: %v", err) + return false + } + fuzzerBin, err := inst.Copy(filepath.Join(mgr.cfg.Syzkaller, "bin/syz-fuzzer")) + if err != nil { logf(0, "failed to copy binary: %v", err) return false } - if err := inst.Copy(filepath.Join(mgr.cfg.Syzkaller, "bin/syz-executor"), "/syz-executor"); err != nil { + executorBin, err := inst.Copy(filepath.Join(mgr.cfg.Syzkaller, "bin/syz-executor")) + if err != nil { logf(0, "failed to copy binary: %v", err) return false } @@ -201,8 +208,8 @@ func (mgr *Manager) runInstance(vmCfg *vm.Config, first bool) bool { // Leak detection significantly slows down fuzzing, so detect leaks only on the first instance. leak := first && mgr.cfg.Leak - outputC, errorC, err := inst.Run(time.Hour, fmt.Sprintf("/syz-fuzzer -name %v -executor /syz-executor -manager %v:%v -output=%v -procs %v -leak=%v %v %v %v", - vmCfg.Name, inst.HostAddr(), mgr.port, mgr.cfg.Output, mgr.cfg.Procs, leak, cover, dropprivs, calls)) + outputC, errorC, err := inst.Run(time.Hour, fmt.Sprintf("%v -executor %v -name %v -manager %v -output=%v -procs %v -leak=%v %v %v %v", + fuzzerBin, executorBin, vmCfg.Name, fwdAddr, mgr.cfg.Output, mgr.cfg.Procs, leak, cover, dropprivs, calls)) if err != nil { logf(0, "failed to run fuzzer: %v", err) return false @@ -221,6 +228,7 @@ func (mgr *Manager) runInstance(vmCfg *vm.Config, first bool) bool { logf(0, "%v: running long enough, restarting", vmCfg.Name) return true default: + logf(0, "%v: lost connection: %v", vmCfg.Name, err) mgr.saveCrasher(vmCfg.Name, "lost connection", output) return true } diff --git a/tools/syz-repro/repro.go b/tools/syz-repro/repro.go index 66a9fff7f..ef633ed0d 100644 --- a/tools/syz-repro/repro.go +++ b/tools/syz-repro/repro.go @@ -26,10 +26,16 @@ var ( flagConfig = flag.String("config", "", "configuration file") flagCount = flag.Int("count", 0, "number of VMs to use (overrides config count param)") - instances chan vm.Instance + instances chan VM bootRequests chan bool ) +type VM struct { + vm.Instance + execprogBin string + executorBin string +} + func main() { flag.Parse() cfg, _, _, err := config.Parse(*flagConfig) @@ -56,7 +62,7 @@ func main() { } log.Printf("target crash: '%s'", data[crashLoc[0]:crashLoc[1]]) - instances = make(chan vm.Instance, cfg.Count) + instances = make(chan VM, cfg.Count) bootRequests = make(chan bool, cfg.Count) for i := 0; i < cfg.Count; i++ { bootRequests <- true @@ -70,13 +76,15 @@ func main() { if err != nil { log.Fatalf("failed to create VM: %v", err) } - if err := inst.Copy(filepath.Join(cfg.Syzkaller, "bin/syz-execprog"), "/syz-execprog"); err != nil { + execprogBin, err := inst.Copy(filepath.Join(cfg.Syzkaller, "bin/syz-execprog")) + if err != nil { log.Fatalf("failed to copy to VM: %v", err) } - if err := inst.Copy(filepath.Join(cfg.Syzkaller, "bin/syz-executor"), "/syz-executor"); err != nil { + executorBin, err := inst.Copy(filepath.Join(cfg.Syzkaller, "bin/syz-executor")) + if err != nil { log.Fatalf("failed to copy to VM: %v", err) } - instances <- inst + instances <- VM{inst, execprogBin, executorBin} } }() } @@ -165,7 +173,7 @@ func repro(cfg *config.Config, entries []*prog.LogEntry, crashLoc []int) { testBin(cfg, bin) } -func returnInstance(inst vm.Instance, res bool) { +func returnInstance(inst VM, res bool) { if res { // The test crashed, discard the VM and issue another boot request. bootRequests <- true @@ -189,7 +197,8 @@ func testProg(cfg *config.Config, p *prog.Prog, multiplier int, threaded, collid log.Fatalf("%v", err) } defer os.Remove(progFile) - if err := inst.Copy(progFile, "/syz-prog"); err != nil { + bin, err := inst.Copy(progFile) + if err != nil { log.Fatalf("failed to copy to VM: %v", err) } @@ -202,8 +211,8 @@ func testProg(cfg *config.Config, p *prog.Prog, multiplier int, threaded, collid repeat *= multiplier timeoutSec *= multiplier timeout := time.Duration(timeoutSec) * time.Second - command := fmt.Sprintf("/syz-execprog -executor /syz-executor -cover=0 -procs=%v -repeat=%v -threaded=%v -collide=%v /syz-prog", - cfg.Procs, repeat, threaded, collide) + command := fmt.Sprintf("%v -executor %v -cover=0 -procs=%v -repeat=%v -threaded=%v -collide=%v %v", + inst.execprogBin, inst.executorBin, cfg.Procs, repeat, threaded, collide, bin) log.Printf("testing program (threaded=%v, collide=%v, repeat=%v, timeout=%v):\n%s\n", threaded, collide, repeat, timeout, pstr) return testImpl(inst, command, timeout) @@ -216,11 +225,12 @@ func testBin(cfg *config.Config, bin string) (res bool) { returnInstance(inst, res) }() - if err := inst.Copy(bin, "/syz-bin"); err != nil { + bin, err := inst.Copy(bin) + if err != nil { log.Fatalf("failed to copy to VM: %v", err) } log.Printf("testing compiled C program") - return testImpl(inst, "/syz-bin", 10*time.Second) + return testImpl(inst, bin, 10*time.Second) } func testImpl(inst vm.Instance, command string, timeout time.Duration) (res bool) { diff --git a/vm/kvm/kvm.go b/vm/kvm/kvm.go index 819008b74..40add4604 100644 --- a/vm/kvm/kvm.go +++ b/vm/kvm/kvm.go @@ -19,6 +19,10 @@ import ( "github.com/google/syzkaller/vm" ) +const ( + hostAddr = "192.168.33.1" +) + func init() { vm.Register("kvm", ctor) } @@ -165,10 +169,6 @@ func validateConfig(cfg *vm.Config) error { return nil } -func (inst *instance) HostAddr() string { - return "192.168.33.1" -} - func (inst *instance) Close() { if inst.lkvm != nil { inst.lkvm.Process.Kill() @@ -181,12 +181,20 @@ func (inst *instance) Close() { os.Remove(inst.sandboxPath + ".sock") } -func (inst *instance) Copy(hostSrc, vmDst string) error { +func (inst *instance) Forward(port int) (string, error) { + return fmt.Sprintf("%v:%v", hostAddr, port), nil +} + +func (inst *instance) Copy(hostSrc string) (string, error) { + vmDst := filepath.Join("/", filepath.Base(hostSrc)) dst := filepath.Join(inst.sandboxPath, vmDst) if err := fileutil.CopyFile(hostSrc, dst, false); err != nil { - return err + return "", err + } + if err := os.Chmod(dst, 0777); err != nil { + return "", err } - return os.Chmod(dst, 0777) + return vmDst, nil } func (inst *instance) Run(timeout time.Duration, command string) (<-chan []byte, <-chan error, error) { diff --git a/vm/local/local.go b/vm/local/local.go index f2d12244c..d81541a06 100644 --- a/vm/local/local.go +++ b/vm/local/local.go @@ -23,7 +23,6 @@ func init() { type instance struct { cfg *vm.Config closed chan bool - files map[string]string } func ctor(cfg *vm.Config) (vm.Instance, error) { @@ -40,27 +39,28 @@ func ctor(cfg *vm.Config) (vm.Instance, error) { inst := &instance{ cfg: cfg, closed: make(chan bool), - files: make(map[string]string), } return inst, nil } -func (inst *instance) HostAddr() string { - return "127.0.0.1" -} - func (inst *instance) Close() { close(inst.closed) os.RemoveAll(inst.cfg.Workdir) } -func (inst *instance) Copy(hostSrc, vmDst string) error { - dst := filepath.Join(inst.cfg.Workdir, vmDst) - inst.files[vmDst] = dst - if err := fileutil.CopyFile(hostSrc, dst, false); err != nil { - return err +func (inst *instance) Forward(port int) (string, error) { + return fmt.Sprintf("127.0.0.1:%v", port), nil +} + +func (inst *instance) Copy(hostSrc string) (string, error) { + vmDst := filepath.Join(inst.cfg.Workdir, filepath.Base(hostSrc)) + if err := fileutil.CopyFile(hostSrc, vmDst, false); err != nil { + return "", err } - return os.Chmod(dst, 0777) + if err := os.Chmod(vmDst, 0777); err != nil { + return "", err + } + return vmDst, nil } func (inst *instance) Run(timeout time.Duration, command string) (<-chan []byte, <-chan error, error) { @@ -68,11 +68,6 @@ func (inst *instance) Run(timeout time.Duration, command string) (<-chan []byte, command = strings.Replace(command, " ", " ", -1) } args := strings.Split(command, " ") - for i, arg := range args { - if inst.files[arg] != "" { - args[i] = inst.files[arg] - } - } cmd := exec.Command(args[0], args[1:]...) if err := cmd.Start(); err != nil { return nil, nil, err diff --git a/vm/qemu/qemu.go b/vm/qemu/qemu.go index 8a9399b89..d9de1d650 100644 --- a/vm/qemu/qemu.go +++ b/vm/qemu/qemu.go @@ -20,6 +20,10 @@ import ( "github.com/google/syzkaller/vm" ) +const ( + hostAddr = "10.0.2.10" +) + func init() { vm.Register("qemu", ctor) } @@ -111,10 +115,6 @@ func validateConfig(cfg *vm.Config) error { return nil } -func (inst *instance) HostAddr() string { - return "10.0.2.10" -} - func (inst *instance) Close() { if inst.qemu != nil { inst.qemu.Process.Kill() @@ -146,7 +146,7 @@ func (inst *instance) Boot() error { "-hda", inst.image, "-m", strconv.Itoa(inst.cfg.Mem), "-net", "nic", - "-net", fmt.Sprintf("user,host=%v,hostfwd=tcp::%v-:22", inst.HostAddr(), inst.port), + "-net", fmt.Sprintf("user,host=%v,hostfwd=tcp::%v-:22", hostAddr, inst.port), "-nographic", "-enable-kvm", "-numa", "node,nodeid=0,cpus=0-1", "-numa", "node,nodeid=1,cpus=2-3", @@ -247,11 +247,16 @@ func (inst *instance) Boot() error { return nil } -func (inst *instance) Copy(hostSrc, vmDst string) error { +func (inst *instance) Forward(port int) (string, error) { + return fmt.Sprintf("%v:%v", hostAddr, port), nil +} + +func (inst *instance) Copy(hostSrc string) (string, error) { + vmDst := filepath.Join("/", filepath.Base(hostSrc)) args := append(inst.sshArgs("-P"), hostSrc, "root@localhost:"+vmDst) cmd := exec.Command("scp", args...) if err := cmd.Start(); err != nil { - return err + return "", err } done := make(chan bool) go func() { @@ -263,7 +268,10 @@ func (inst *instance) Copy(hostSrc, vmDst string) error { }() err := cmd.Wait() close(done) - return err + if err != nil { + return "", err + } + return vmDst, nil } func (inst *instance) Run(timeout time.Duration, command string) (<-chan []byte, <-chan error, error) { @@ -12,30 +12,35 @@ import ( // Instance represents a Linux VM or a remote physical machine. type Instance interface { - // Copy copies a hostSrc file to vmDst file (think of scp). - Copy(hostSrc, vmDst string) error + // Copy copies a hostSrc file into vm and returns file name in vm. + Copy(hostSrc string) (string, error) + + // Forward setups forwarding from within VM to host port port + // and returns address to use in VM. + Forward(port int) (string, error) + // Run runs cmd inside of the VM (think of ssh cmd). // outc receives combined cmd and kernel console output. // errc receives either command Wait return error or vm.TimeoutErr. Run(timeout time.Duration, command string) (outc <-chan []byte, errc <-chan error, err error) - // HostAddr returns ip address of the host as seen by the VM. - HostAddr() string + // Close stops and destroys the VM. Close() } type Config struct { - Name string - Index int - Workdir string - Bin string - Kernel string - Cmdline string - Image string - Sshkey string - Cpu int - Mem int - Debug bool + Name string + Index int + Workdir string + Bin string + Kernel string + Cmdline string + Image string + Sshkey string + ConsoleDev string + Cpu int + Mem int + Debug bool } type ctorFunc func(cfg *Config) (Instance, error) |
