aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2016-01-11 17:33:44 +0100
committerDmitry Vyukov <dvyukov@google.com>2016-01-11 17:33:44 +0100
commitde48f7b019027f72dc84f56e9e5f0cb03645294e (patch)
tree373842f113b5bc3fbefde37444e375a19dca8dcf
parent46fa57f3b44ccbecfb20067778dae9a7f5a111a5 (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.go25
-rw-r--r--syz-manager/manager.go16
-rw-r--r--tools/syz-repro/repro.go32
-rw-r--r--vm/kvm/kvm.go22
-rw-r--r--vm/local/local.go29
-rw-r--r--vm/qemu/qemu.go24
-rw-r--r--vm/vm.go35
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) {
diff --git a/vm/vm.go b/vm/vm.go
index ea2e367c7..34aa43a14 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -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)