diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2017-02-06 16:01:45 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2017-02-06 16:01:45 +0100 |
| commit | c81cc207a69c4efeb8ca07090ef1427a13324a0b (patch) | |
| tree | ce0119534a2c92e0d402ed941474c3b277fbc9e7 | |
| parent | 971d338aa9799952f430bc08bf8fa0cde39b420e (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.go | 36 | ||||
| -rw-r--r-- | vm/adb/console.go | 57 |
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 +} |
