mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-23 19:39:40 +00:00
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.
This commit is contained in:
parent
46fa57f3b4
commit
de48f7b019
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
return os.Chmod(dst, 0777)
|
||||
if err := os.Chmod(dst, 0777); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return vmDst, nil
|
||||
}
|
||||
|
||||
func (inst *instance) Run(timeout time.Duration, command string) (<-chan []byte, <-chan error, error) {
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
35
vm/vm.go
35
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)
|
||||
|
Loading…
Reference in New Issue
Block a user