aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-02-06 16:01:45 +0100
committerDmitry Vyukov <dvyukov@google.com>2017-02-06 16:01:45 +0100
commitc81cc207a69c4efeb8ca07090ef1427a13324a0b (patch)
treece0119534a2c92e0d402ed941474c3b277fbc9e7
parent971d338aa9799952f430bc08bf8fa0cde39b420e (diff)
vm/adb: support fuzzing without console
If no console found, fall back to 'adb shell dmesg -w'. This is not reliable, and lots of bugs are detected as 'lost connection' without any kernel output. But users want this.
-rw-r--r--vm/adb/adb.go36
-rw-r--r--vm/adb/console.go57
2 files changed, 83 insertions, 10 deletions
diff --git a/vm/adb/adb.go b/vm/adb/adb.go
index cb2f5ae33..fcc62574f 100644
--- a/vm/adb/adb.go
+++ b/vm/adb/adb.go
@@ -46,10 +46,7 @@ func ctor(cfg *vm.Config) (vm.Instance, error) {
if err := inst.repair(); err != nil {
return nil, err
}
- var err error
- if inst.console, err = findConsole(inst.cfg.Bin, inst.cfg.Device); err != nil {
- return nil, err
- }
+ inst.console = findConsole(inst.cfg.Bin, inst.cfg.Device)
if err := inst.checkBatteryLevel(); err != nil {
return nil, err
}
@@ -83,12 +80,28 @@ var (
// while Suzy-Q console uses the same USB calbe as adb.
// The overall idea is as follows. We use 'adb shell' to write a unique string onto console,
// then we read from all console devices and see on what console the unique string appears.
-func findConsole(adb, dev string) (string, error) {
+func findConsole(adb, dev string) string {
consoleCacheMu.Lock()
defer consoleCacheMu.Unlock()
if con := devToConsole[dev]; con != "" {
- return con, nil
+ return con
+ }
+ con, err := findConsoleImpl(adb, dev)
+ if err != nil {
+ Logf(0, "failed to associate adb device %v with console: %v", dev, err)
+ Logf(0, "falling back to 'adb shell dmesg -w'")
+ Logf(0, "note: some bugs may be detected as 'lost connection to test machine' with no kernel output")
+ con = "adb"
+ devToConsole[dev] = con
+ return con
}
+ devToConsole[dev] = con
+ consoleToDev[con] = dev
+ Logf(0, "associating adb device %v with console %v", dev, con)
+ return con
+}
+
+func findConsoleImpl(adb, dev string) (string, error) {
consoles, err := filepath.Glob("/dev/ttyUSB*")
if err != nil {
return "", fmt.Errorf("failed to list /dev/ttyUSB devices: %v", err)
@@ -154,9 +167,6 @@ func findConsole(adb, dev string) (string, error) {
}
return "", fmt.Errorf("no console is associated with this device")
}
- devToConsole[dev] = con
- consoleToDev[con] = dev
- Logf(0, "associating adb device %v with console %v", dev, con)
return con, nil
}
@@ -327,7 +337,13 @@ func (inst *instance) Copy(hostSrc string) (string, error) {
}
func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command string) (<-chan []byte, <-chan error, error) {
- tty, err := openConsole(inst.console)
+ var tty io.ReadCloser
+ var err error
+ if inst.console == "adb" {
+ tty, err = openAdbConsole(inst.cfg.Bin, inst.cfg.Device)
+ } else {
+ tty, err = openConsole(inst.console)
+ }
if err != nil {
return nil, nil, err
}
diff --git a/vm/adb/console.go b/vm/adb/console.go
index e55e019ae..8c56c7d1b 100644
--- a/vm/adb/console.go
+++ b/vm/adb/console.go
@@ -6,10 +6,12 @@ package adb
import (
"fmt"
"io"
+ "os/exec"
"sync"
"syscall"
"unsafe"
+ "github.com/google/syzkaller/vm"
. "golang.org/x/sys/unix"
)
@@ -73,3 +75,58 @@ func (t *tty) Close() error {
}
return nil
}
+
+// openAdbConsole provides fallback console output using 'adb shell dmesg -w'.
+func openAdbConsole(bin, dev string) (rc io.ReadCloser, err error) {
+ rpipe, wpipe, err := vm.LongPipe()
+ if err != nil {
+ return nil, err
+ }
+ cmd := exec.Command(bin, "-s", dev, "shell", "dmesg -w")
+ cmd.Stdout = wpipe
+ cmd.Stderr = wpipe
+ if err := cmd.Start(); err != nil {
+ rpipe.Close()
+ wpipe.Close()
+ return nil, fmt.Errorf("failed to start adb: %v", err)
+ }
+ wpipe.Close()
+ con := &adbCon{
+ cmd: cmd,
+ rpipe: rpipe,
+ }
+ return con, err
+}
+
+type adbCon struct {
+ closeMu sync.Mutex
+ readMu sync.Mutex
+ cmd *exec.Cmd
+ rpipe io.ReadCloser
+}
+
+func (t *adbCon) Read(buf []byte) (int, error) {
+ t.readMu.Lock()
+ n, err := t.rpipe.Read(buf)
+ t.readMu.Unlock()
+ return n, err
+}
+
+func (t *adbCon) Close() error {
+ t.closeMu.Lock()
+ cmd := t.cmd
+ t.cmd = nil
+ t.closeMu.Unlock()
+ if cmd == nil {
+ return nil
+ }
+
+ cmd.Process.Kill()
+
+ t.readMu.Lock()
+ t.rpipe.Close()
+ t.readMu.Unlock()
+
+ cmd.Process.Wait()
+ return nil
+}