Skip to content

Commit

Permalink
vm: Make the adbemu compatible with newly mergerd version
Browse files Browse the repository at this point in the history
  • Loading branch information
superguo committed Jul 14, 2017
1 parent beaf3de commit 6d4158d
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 99 deletions.
14 changes: 8 additions & 6 deletions android.cfg
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
{
"http": "localhost:5000",
"workdir": "/home/w4118/syzkaller/workdir",
"avd": "x86",
"kernel": "/home/w4118/utils/goldfish/arch/x86/boot/bzImage",
"vmlinux": "-",
"vmlinux": "/home/w4118/utils/goldfish/vmlinux",
"syzkaller": "/home/w4118/syzkaller",
"type": "adbemu",
"procs": 1,
"count": 2,
"procs": 2,
"cover": true,
"sandbox": "none",
"enable_syscalls": [
"syz_open_dev$binder", "ioctl$BINDER_VERSION", "ioctl$BINDER_WRITE_READ", "ioctl$BINDER_SET_IDLE_TIMEOUT", "ioctl$BINDER_SET_MAX_THREADS", "ioctl$BINDER_SET_IDLE_PRIORITY", "ioctl$BINDER_SET_CONTEXT_MGR", "ioctl$BINDER_THREAD_EXIT",
"syz_open_dev$ion", "ioctl$ION_IOC_ALLOC", "ioctl$ION_IOC_FREE", "ioctl$ION_IOC_MAP", "ioctl$ION_IOC_SHARE", "ioctl$ION_IOC_IMPORT", "ioctl$ION_IOC_SYNC",
"syz_open_dev$ashmem", "ioctl$ASHMEM_SET_NAME", "ioctl$ASHMEM_GET_NAME", "ioctl$ASHMEM_SET_SIZE", "ioctl$ASHMEM_GET_SIZE", "ioctl$ASHMEM_SET_PROT_MASK", "ioctl$ASHMEM_GET_PROT_MASK", "ioctl$ASHMEM_PIN", "ioctl$ASHMEM_UNPIN", "ioctl$ASHMEM_GET_PIN_STATUS", "ioctl$ASHMEM_PURGE_ALL_CACHES", "mmap$fd_ashmem", "munmap$fd_ashmem", "read$fd_ashmem", "write$fd_ashmem"
]
],
"vm": {
"avd": "x86",
"count": 4,
"kernel": "/home/w4118/utils/goldfish/arch/x86/boot/bzImage"
}
}

204 changes: 111 additions & 93 deletions vm/adbemu/adbemu.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,62 +16,124 @@ import (
"time"
"bufio"

. "github.com/google/syzkaller/log"
"github.com/google/syzkaller/vm"
"github.com/google/syzkaller/pkg/config"
. "github.com/google/syzkaller/pkg/log"
"github.com/google/syzkaller/pkg/osutil"
"github.com/google/syzkaller/vm/vmimpl"
)

const (
hostAddr = "10.0.2.10"
)

func init() {
vm.Register("adbemu", ctor)
vmimpl.Register("adbemu", ctor)
}

type Config struct {
Count int // number of VMs to use
SdkPath string // Optional path to the Android SDK or obtained from environment variable ANDROID_SDK
AdbBin string // Optional adb path. Must be set if sdk path could not be determined
Emu string // Optional emulator binary path. Must be set if sdk path could not be determined
Avd string // Android virtual device name for emulator -avd argument (without "@")
Kernel string // Path to kernel image e.g. arch/x86/boot/bzImage
Avd_Args string // Additional Android emulator arguments (before -qemu after -avd $Avd)
Qemu_Args string // Additional Android emulator arguments (after -qemu)
}

type Pool struct {
env *vmimpl.Env
cfg *Config
}

type instance struct {
cfg *vm.Config
cfg *Config
port int
workdir string
rpipe io.ReadCloser
wpipe io.WriteCloser
qemu *exec.Cmd
waiterC chan error
merger *vm.OutputMerger
merger *vmimpl.OutputMerger
debug bool

// Android stuffs
device string
sdkPath string
}

func ctor(cfg *vm.Config) (vm.Instance, error) {
for i := 0; ; i++ {
inst, err := ctorImpl(cfg)
if err == nil {
return inst, nil
}
if i < 1000 && strings.Contains(err.Error(), "could not set up host forwarding rule") {
continue
}
os.RemoveAll(cfg.Workdir)
func ctor(env *vmimpl.Env) (vmimpl.Pool, error) {
cfg := &Config{
Count: 1,
SdkPath: "",
AdbBin: "",
Emu: "",
Avd: "",
Kernel: "",
Avd_Args: "-verbose -wipe-data -show-kernel -no-window",
Qemu_Args: "-enable-kvm",
}

if err := config.LoadData(env.Config, cfg); err != nil {
return nil, err
}
if cfg.Count < 1 || cfg.Count > 1000 {
return nil, fmt.Errorf("invalid config param count: %v, want [1, 1000]", cfg.Count)
}
if env.Debug {
cfg.Count = 1
}

if env.Image == "9p" {
return nil, fmt.Errorf("9p image is not unsupported")
}
if cfg.Kernel != "" {
if _, err := os.Stat(cfg.Kernel); err != nil {
return nil, fmt.Errorf("kernel image file '%v' does not exist: %v", cfg.Kernel, err)
}
}
if cfg.SdkPath == "" {
cfg.SdkPath = os.Getenv("ANDROID_SDK")
}
if cfg.SdkPath == "" {
return nil, fmt.Errorf("ANDROID_SDK must be set")
}
if cfg.AdbBin == "" {
cfg.AdbBin = cfg.SdkPath + "/platform-tools/adb"
}
if cfg.Emu == "" {
cfg.Emu = cfg.SdkPath + "/tools/emulator"
}
if !containsAvd(cfg.Emu, cfg.Avd) {
return nil, fmt.Errorf("avd '%v' doest not exist", cfg.Avd)
}
pool := &Pool{
cfg: cfg,
env: env,
}
return pool, nil
}

func ctorImpl(cfg *vm.Config) (vm.Instance, error) {
inst := &instance{cfg: cfg}
func (pool *Pool) Count() int {
return pool.cfg.Count
}

func (pool *Pool) Create(workdir string, index int) (vmimpl.Instance, error) {
inst := &instance{
cfg: pool.cfg,
// closed: make(chan bool),
workdir: workdir,
debug: pool.env.Debug,
}

closeInst := inst
defer func() {
if closeInst != nil {
closeInst.close(false)
closeInst.Close()
}
}()

inst.sdkPath = os.Getenv("ANDROID_SDK")
if err := validateConfig(cfg, inst.sdkPath); err != nil {
return nil, err
}

var err error
inst.rpipe, inst.wpipe, err = vm.LongPipe()
inst.rpipe, inst.wpipe, err = osutil.LongPipe()
if err != nil {
return nil, err
}
Expand All @@ -84,7 +146,6 @@ func ctorImpl(cfg *vm.Config) (vm.Instance, error) {
return inst, nil
}


func containsAvd(emulatorPath string, avd string) bool {
cmd := exec.Command(emulatorPath, "-list-avds")
stdout, err := cmd.StdoutPipe()
Expand All @@ -108,27 +169,6 @@ func containsAvd(emulatorPath string, avd string) bool {
return false
}

func validateConfig(cfg *vm.Config, sdkPath string) error {
if cfg.Bin == "" {
if sdkPath == "" {
return fmt.Errorf("ANDROID_SDK must be set")
}
cfg.Bin = sdkPath + "/tools/emulator"
}
if cfg.Image == "9p" {
return fmt.Errorf("9p image is not unsupported")
}
if cfg.Kernel != "" {
if _, err := os.Stat(cfg.Kernel); err != nil {
return fmt.Errorf("kernel image file '%v' does not exist: %v", cfg.Image, err)
}
}
if !containsAvd(cfg.Bin, cfg.Avd) {
return fmt.Errorf("avd '%v' doest not exist", cfg.Avd)
}
return nil
}


func (inst *instance) Close() {
inst.close(true)
Expand All @@ -149,9 +189,9 @@ func (inst *instance) close(removeWorkDir bool) {
if inst.wpipe != nil {
inst.wpipe.Close()
}
os.Remove(filepath.Join(inst.cfg.Workdir, "key"))
os.Remove(filepath.Join(inst.workdir, "key"))
if removeWorkDir {
os.RemoveAll(inst.cfg.Workdir)
os.RemoveAll(inst.workdir)
}
}

Expand All @@ -171,44 +211,23 @@ func (inst *instance) Boot() error {
args = append(args, "-kernel", inst.cfg.Kernel)
}

// arguments before -qemu
if inst.cfg.AvdArgs == "" {
// This is reasonable defaults for Android emulator.
args = append(args,
"-verbose",
"-wipe-data",
"-show-kernel",
"-no-window",
)
} else {
args = append(args, strings.Split(inst.cfg.AvdArgs, " ")...)
}
// Avd_Args are the arguments before -qemu
// For default value, see func ctor(env *vmimpl.Env) (vmimpl.Pool, error)
args = append(args, strings.Split(inst.cfg.Avd_Args, " ")...)

// Bin_Args is following '-qemu' so as not to change its meaning.
// To change the arguments before -qemu, use Avd_Args
// Qemu_Args are arguments after '-qemu'
// For default value, see func ctor(env *vmimpl.Env) (vmimpl.Pool, error)
args = append(args, "-qemu")
if inst.cfg.BinArgs == "" {
// This is reasonable defaults for kvm-enabled host.
args = append(args, "-enable-kvm")
} else {
args = append(args, strings.Split(inst.cfg.BinArgs, " ")...)
}

// This argument must be added after -qemu
if inst.cfg.Initrd != "" {
args = append(args,
"-initrd", inst.cfg.Initrd,
)
}
args = append(args, strings.Split(inst.cfg.Qemu_Args, " ")...)

if inst.cfg.Debug {
Logf(0, "running command: %v %#v", inst.cfg.Bin, args)
if inst.debug {
Logf(0, "running command: %v %#v", inst.cfg.Emu, args)
}
qemu := exec.Command(inst.cfg.Bin, args...)
qemu := exec.Command(inst.cfg.Emu, args...)
qemu.Stdout = inst.wpipe
qemu.Stderr = inst.wpipe
if err := qemu.Start(); err != nil {
return fmt.Errorf("failed to start %v %+v: %v", inst.cfg.Bin, args, err)
return fmt.Errorf("failed to start %v %+v: %v", inst.cfg.Emu, args, err)
}
inst.wpipe.Close()
inst.wpipe = nil
Expand All @@ -217,10 +236,10 @@ func (inst *instance) Boot() error {

// Start output merger.
var tee io.Writer
if inst.cfg.Debug {
if inst.debug {
tee = os.Stdout
}
inst.merger = vm.NewOutputMerger(tee)
inst.merger = vmimpl.NewOutputMerger(tee)
inst.merger.Add("qemu", inst.rpipe)
inst.rpipe = nil

Expand All @@ -246,7 +265,7 @@ func (inst *instance) Boot() error {
}()

// Wait for device serial number to appear.
if inst.cfg.Debug {
if inst.debug {
Logf(0, "Looking for Android device sn")
}
time.Sleep(10 * time.Second)
Expand Down Expand Up @@ -298,7 +317,7 @@ func (inst *instance) Forward(port int) (string, error) {

func (inst *instance) adb(args ...string) ([]byte, error) {
args = append([]string{"-s", inst.device}, args...)
if inst.cfg.Debug {
if inst.debug {
Logf(0, "running command: adb %+v", args)
}
rpipe, wpipe, err := os.Pipe()
Expand All @@ -307,8 +326,7 @@ func (inst *instance) adb(args ...string) ([]byte, error) {
}
defer wpipe.Close()
defer rpipe.Close()
adbPath := inst.sdkPath + "/platform-tools/adb"
cmd := exec.Command(adbPath, args...)
cmd := exec.Command(inst.cfg.AdbBin, args...)
cmd.Stdout = wpipe
cmd.Stderr = wpipe
if err := cmd.Start(); err != nil {
Expand All @@ -327,13 +345,13 @@ func (inst *instance) adb(args ...string) ([]byte, error) {
if err := cmd.Wait(); err != nil {
close(done)
out, _ := ioutil.ReadAll(rpipe)
if inst.cfg.Debug {
if inst.debug {
Logf(0, "adb failed: %v\n%s", err, out)
}
return nil, fmt.Errorf("adb %+v failed: %v\n%s", args, err, out)
}
close(done)
if inst.cfg.Debug {
if inst.debug {
Logf(0, "adb returned")
}
out, _ := ioutil.ReadAll(rpipe)
Expand All @@ -352,7 +370,7 @@ func (inst *instance) Copy(hostSrc string) (string, error) {
/* Run command via adb shell */
func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command string) (<-chan []byte, <-chan error, error) {

adbRpipe, adbWpipe, err := vm.LongPipe()
adbRpipe, adbWpipe, err := osutil.LongPipe()
if err != nil {
inst.qemu.Process.Kill()
// Do not close the inst.rpipe 'cause it will be closed in merger
Expand All @@ -361,7 +379,7 @@ func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command strin
return nil, nil, err
}

if inst.cfg.Debug {
if inst.debug {
Logf(0, "running command: adb -s %v shell %v", inst.device, command)
}

Expand All @@ -380,7 +398,7 @@ func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command strin
adbDone := make(chan error, 1)
go func() {
err := adb.Wait()
if inst.cfg.Debug {
if inst.debug {
Logf(0, "adb exited: %v", err)
}
adbDone <- fmt.Errorf("adb exited: %v", err)
Expand All @@ -399,11 +417,11 @@ func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command strin
go func() {
select {
case <-time.After(timeout):
signal(vm.TimeoutErr)
signal(vmimpl.TimeoutErr)
inst.qemu.Process.Kill()
adb.Process.Kill()
case <-stop:
signal(vm.TimeoutErr)
signal(vmimpl.TimeoutErr)
inst.qemu.Process.Kill()
adb.Process.Kill()
case err := <-adbDone:
Expand Down
1 change: 1 addition & 0 deletions vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/google/syzkaller/vm/vmimpl"

_ "github.com/google/syzkaller/vm/adb"
_ "github.com/google/syzkaller/vm/adbemu"
_ "github.com/google/syzkaller/vm/gce"
_ "github.com/google/syzkaller/vm/kvm"
_ "github.com/google/syzkaller/vm/odroid"
Expand Down

0 comments on commit 6d4158d

Please sign in to comment.