mirror of
https://github.com/reactos/syzkaller.git
synced 2024-10-07 17:13:26 +00:00
vm/adb: support multiple adb devices
Device IDs are specified in "devices" config param.
This commit is contained in:
parent
26a5cf9efa
commit
bc9b349bd7
@ -34,10 +34,11 @@ type Config struct {
|
||||
Debug bool // dump all VM output to console
|
||||
Output string // one of stdout/dmesg/file (useful only for local VM)
|
||||
|
||||
Syzkaller string // path to syzkaller checkout (syz-manager will look for binaries in bin subdir)
|
||||
Type string // VM type (qemu, kvm, local)
|
||||
Count int // number of VMs
|
||||
Procs int // number of parallel processes inside of every VM
|
||||
Syzkaller string // path to syzkaller checkout (syz-manager will look for binaries in bin subdir)
|
||||
Type string // VM type (qemu, kvm, local)
|
||||
Count int // number of VMs (don't secify for adb, instead specify devices)
|
||||
Devices []string // device IDs for adb
|
||||
Procs int // number of parallel processes inside of every VM
|
||||
|
||||
Sandbox string // type of sandbox to use during fuzzing:
|
||||
// "none": don't do anything special (has false positives, e.g. due to killing init)
|
||||
@ -48,8 +49,6 @@ type Config struct {
|
||||
Cover bool // use kcov coverage (default: true)
|
||||
Leak bool // do memory leak checking
|
||||
|
||||
ConsoleDev string // console device for adb vm
|
||||
|
||||
Enable_Syscalls []string
|
||||
Disable_Syscalls []string
|
||||
Suppressions []string
|
||||
@ -98,21 +97,36 @@ func parse(data []byte) (*Config, map[int]bool, []*regexp.Regexp, error) {
|
||||
if cfg.Type == "" {
|
||||
return nil, nil, nil, fmt.Errorf("config param type is empty")
|
||||
}
|
||||
if cfg.Type == "none" {
|
||||
switch cfg.Type {
|
||||
case "none":
|
||||
if cfg.Count != 0 {
|
||||
return nil, nil, nil, fmt.Errorf("invalid config param count: %v, type \"none\" does not support param count", cfg.Count)
|
||||
}
|
||||
if cfg.Rpc == "" {
|
||||
return nil, nil, nil, fmt.Errorf("config param rpc is empty (required for type \"none\")")
|
||||
}
|
||||
} else {
|
||||
if len(cfg.Devices) != 0 {
|
||||
return nil, nil, nil, fmt.Errorf("type %v does not support devices param", cfg.Type)
|
||||
}
|
||||
case "adb":
|
||||
if cfg.Count != 0 {
|
||||
return nil, nil, nil, fmt.Errorf("don't specify count for adb, instead specify devices")
|
||||
}
|
||||
if len(cfg.Devices) == 0 {
|
||||
return nil, nil, nil, fmt.Errorf("specify at least 1 adb device")
|
||||
}
|
||||
cfg.Count = len(cfg.Devices)
|
||||
default:
|
||||
if cfg.Count <= 0 || cfg.Count > 1000 {
|
||||
return nil, nil, nil, fmt.Errorf("invalid config param count: %v, want (1, 1000]", cfg.Count)
|
||||
}
|
||||
if cfg.Rpc == "" {
|
||||
cfg.Rpc = "localhost:0"
|
||||
if len(cfg.Devices) != 0 {
|
||||
return nil, nil, nil, fmt.Errorf("type %v does not support devices param", cfg.Type)
|
||||
}
|
||||
}
|
||||
if cfg.Rpc == "" {
|
||||
cfg.Rpc = "localhost:0"
|
||||
}
|
||||
if cfg.Procs <= 0 {
|
||||
cfg.Procs = 1
|
||||
}
|
||||
@ -219,26 +233,31 @@ func parseSuppressions(cfg *Config) ([]*regexp.Regexp, error) {
|
||||
return suppressions, nil
|
||||
}
|
||||
|
||||
func CreateVMConfig(cfg *Config) (*vm.Config, error) {
|
||||
func CreateVMConfig(cfg *Config, index int) (*vm.Config, error) {
|
||||
if index < 0 || index >= cfg.Count {
|
||||
return nil, fmt.Errorf("invalid VM index %v (count %v)", index, cfg.Count)
|
||||
}
|
||||
workdir, index, err := fileutil.ProcessTempDir(cfg.Workdir)
|
||||
if err != nil {
|
||||
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,
|
||||
Initrd: cfg.Initrd,
|
||||
Sshkey: cfg.Sshkey,
|
||||
Executor: filepath.Join(cfg.Syzkaller, "bin", "syz-executor"),
|
||||
ConsoleDev: cfg.ConsoleDev,
|
||||
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,
|
||||
Initrd: cfg.Initrd,
|
||||
Sshkey: cfg.Sshkey,
|
||||
Executor: filepath.Join(cfg.Syzkaller, "bin", "syz-executor"),
|
||||
Cpu: cfg.Cpu,
|
||||
Mem: cfg.Mem,
|
||||
Debug: cfg.Debug,
|
||||
}
|
||||
if len(cfg.Devices) != 0 {
|
||||
vmCfg.Device = cfg.Devices[index]
|
||||
}
|
||||
return vmCfg, nil
|
||||
}
|
||||
@ -264,11 +283,11 @@ func checkUnknownFields(data []byte) (string, error) {
|
||||
"Syzkaller",
|
||||
"Type",
|
||||
"Count",
|
||||
"Devices",
|
||||
"Procs",
|
||||
"Cover",
|
||||
"Sandbox",
|
||||
"Leak",
|
||||
"ConsoleDev",
|
||||
"Enable_Syscalls",
|
||||
"Disable_Syscalls",
|
||||
"Suppressions",
|
||||
|
@ -166,18 +166,18 @@ func RunManager(cfg *config.Config, syscalls map[int]bool, suppressions []*regex
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(cfg.Count + 1)
|
||||
for i := 0; i < cfg.Count; i++ {
|
||||
first := i == 0
|
||||
i := i
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for {
|
||||
vmCfg, err := config.CreateVMConfig(cfg)
|
||||
vmCfg, err := config.CreateVMConfig(cfg, i)
|
||||
if atomic.LoadUint32(&shutdown) != 0 {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
fatalf("failed to create VM config: %v", err)
|
||||
}
|
||||
ok := mgr.runInstance(vmCfg, first)
|
||||
ok := mgr.runInstance(vmCfg, i == 0)
|
||||
if atomic.LoadUint32(&shutdown) != 0 {
|
||||
break
|
||||
}
|
||||
|
@ -30,12 +30,13 @@ var (
|
||||
flagCount = flag.Int("count", 0, "number of VMs to use (overrides config count param)")
|
||||
|
||||
instances chan VM
|
||||
bootRequests chan bool
|
||||
bootRequests chan int
|
||||
shutdown = make(chan struct{})
|
||||
)
|
||||
|
||||
type VM struct {
|
||||
vm.Instance
|
||||
index int
|
||||
execprogBin string
|
||||
executorBin string
|
||||
}
|
||||
@ -70,12 +71,12 @@ func main() {
|
||||
log.Printf("target crash: '%s'", crashDesc)
|
||||
|
||||
instances = make(chan VM, cfg.Count)
|
||||
bootRequests = make(chan bool, cfg.Count)
|
||||
bootRequests = make(chan int, cfg.Count)
|
||||
for i := 0; i < cfg.Count; i++ {
|
||||
bootRequests <- true
|
||||
bootRequests <- i
|
||||
go func() {
|
||||
for range bootRequests {
|
||||
vmCfg, err := config.CreateVMConfig(cfg)
|
||||
for index := range bootRequests {
|
||||
vmCfg, err := config.CreateVMConfig(cfg, index)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to create VM config: %v", err)
|
||||
}
|
||||
@ -91,7 +92,7 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatalf("failed to copy to VM: %v", err)
|
||||
}
|
||||
instances <- VM{inst, execprogBin, executorBin}
|
||||
instances <- VM{inst, index, execprogBin, executorBin}
|
||||
}
|
||||
}()
|
||||
}
|
||||
@ -197,7 +198,7 @@ func repro(cfg *config.Config, entries []*prog.LogEntry, crashStart int) {
|
||||
func returnInstance(inst VM, res bool) {
|
||||
if res {
|
||||
// The test crashed, discard the VM and issue another boot request.
|
||||
bootRequests <- true
|
||||
bootRequests <- inst.index
|
||||
inst.Close()
|
||||
} else {
|
||||
// The test did not crash, reuse the same VM in future.
|
||||
|
@ -11,6 +11,9 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/syzkaller/vm"
|
||||
@ -21,8 +24,9 @@ func init() {
|
||||
}
|
||||
|
||||
type instance struct {
|
||||
cfg *vm.Config
|
||||
closed chan bool
|
||||
cfg *vm.Config
|
||||
console string
|
||||
closed chan bool
|
||||
}
|
||||
|
||||
func ctor(cfg *vm.Config) (vm.Instance, error) {
|
||||
@ -39,6 +43,9 @@ func ctor(cfg *vm.Config) (vm.Instance, error) {
|
||||
if err := validateConfig(cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := inst.findConsole(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := inst.repair(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -52,12 +59,46 @@ func validateConfig(cfg *vm.Config) error {
|
||||
if cfg.Bin == "" {
|
||||
cfg.Bin = "adb"
|
||||
}
|
||||
if _, err := os.Stat(cfg.ConsoleDev); err != nil {
|
||||
return fmt.Errorf("console device '%v' is missing: %v", cfg.ConsoleDev, err)
|
||||
if !regexp.MustCompile("[0-9A-F]+").MatchString(cfg.Device) {
|
||||
return fmt.Errorf("invalid adb device id '%v'", cfg.Device)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
consoleCacheMu sync.Mutex
|
||||
consoleCache = make(map[string]string)
|
||||
)
|
||||
|
||||
func (inst *instance) findConsole() error {
|
||||
// Case Closed Debugging using Suzy-Q:
|
||||
// https://chromium.googlesource.com/chromiumos/platform/ec/+/master/docs/case_closed_debugging.md
|
||||
consoleCacheMu.Lock()
|
||||
defer consoleCacheMu.Unlock()
|
||||
if inst.console = consoleCache[inst.cfg.Device]; inst.console != "" {
|
||||
return nil
|
||||
}
|
||||
out, err := exec.Command(inst.cfg.Bin, "devices", "-l").CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute 'adb devices -l': %v\n%v\n", err, string(out))
|
||||
}
|
||||
re := regexp.MustCompile(fmt.Sprintf("%v +device usb:([0-9]+)-([0-9]+)\\.([0-9]+) ", inst.cfg.Device))
|
||||
match := re.FindAllStringSubmatch(string(out), 1)
|
||||
if match == nil {
|
||||
return fmt.Errorf("can't find adb device '%v' in 'adb devices' output:\n%v\n", inst.cfg.Device, string(out))
|
||||
}
|
||||
bus, _ := strconv.ParseUint(match[0][1], 10, 64)
|
||||
port, _ := strconv.ParseUint(match[0][2], 10, 64)
|
||||
files, err := filepath.Glob(fmt.Sprintf("/sys/bus/usb/devices/%v-%v.2:1.1/ttyUSB*", bus, port))
|
||||
if err != nil || len(files) == 0 {
|
||||
return fmt.Errorf("can't find any ttyUDB devices for adb device '%v' on bus %v-%v", inst.cfg.Device, bus, port)
|
||||
}
|
||||
inst.console = "/dev/" + filepath.Base(files[0])
|
||||
consoleCache[inst.cfg.Device] = inst.console
|
||||
log.Printf("associating adb device %v with console %v", inst.cfg.Device, inst.console)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (inst *instance) Forward(port int) (string, error) {
|
||||
// If 35099 turns out to be busy, try to forward random ports several times.
|
||||
devicePort := 35099
|
||||
@ -77,7 +118,7 @@ func (inst *instance) adb(args ...string) error {
|
||||
}
|
||||
defer wpipe.Close()
|
||||
defer rpipe.Close()
|
||||
cmd := exec.Command(inst.cfg.Bin, args...)
|
||||
cmd := exec.Command(inst.cfg.Bin, append([]string{"-s", inst.cfg.Device}, args...)...)
|
||||
cmd.Stdout = wpipe
|
||||
cmd.Stderr = wpipe
|
||||
if err := cmd.Start(); err != nil {
|
||||
@ -158,13 +199,13 @@ func (inst *instance) Run(timeout time.Duration, command string) (<-chan []byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
cat := exec.Command("cat", inst.cfg.ConsoleDev)
|
||||
cat := exec.Command("cat", inst.console)
|
||||
cat.Stdout = catWpipe
|
||||
cat.Stderr = catWpipe
|
||||
if err := cat.Start(); err != nil {
|
||||
catRpipe.Close()
|
||||
catWpipe.Close()
|
||||
return nil, nil, fmt.Errorf("failed to start cat %v: %v", inst.cfg.ConsoleDev, err)
|
||||
return nil, nil, fmt.Errorf("failed to start cat %v: %v", inst.console, err)
|
||||
|
||||
}
|
||||
catWpipe.Close()
|
||||
@ -186,7 +227,7 @@ func (inst *instance) Run(timeout time.Duration, command string) (<-chan []byte,
|
||||
if inst.cfg.Debug {
|
||||
log.Printf("starting: adb shell %v", command)
|
||||
}
|
||||
adb := exec.Command(inst.cfg.Bin, "shell", "cd /data; "+command)
|
||||
adb := exec.Command(inst.cfg.Bin, "-s", inst.cfg.Device, "shell", "cd /data; "+command)
|
||||
adb.Stdout = adbWpipe
|
||||
adb.Stderr = adbWpipe
|
||||
if err := adb.Start(); err != nil {
|
||||
|
28
vm/vm.go
28
vm/vm.go
@ -32,20 +32,20 @@ type Instance interface {
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Name string
|
||||
Index int
|
||||
Workdir string
|
||||
Bin string
|
||||
Initrd string
|
||||
Kernel string
|
||||
Cmdline string
|
||||
Image string
|
||||
Sshkey string
|
||||
Executor string
|
||||
ConsoleDev string
|
||||
Cpu int
|
||||
Mem int
|
||||
Debug bool
|
||||
Name string
|
||||
Index int
|
||||
Workdir string
|
||||
Bin string
|
||||
Initrd string
|
||||
Kernel string
|
||||
Cmdline string
|
||||
Image string
|
||||
Sshkey string
|
||||
Executor string
|
||||
Device string
|
||||
Cpu int
|
||||
Mem int
|
||||
Debug bool
|
||||
}
|
||||
|
||||
type ctorFunc func(cfg *Config) (Instance, error)
|
||||
|
Loading…
Reference in New Issue
Block a user