2015-10-12 10:16:57 +02:00
|
|
|
// Copyright 2015 syzkaller project authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package vm
|
|
|
|
|
|
|
|
import (
|
2016-01-19 17:17:40 +01:00
|
|
|
"bytes"
|
2015-12-23 19:11:29 +01:00
|
|
|
"errors"
|
2015-10-12 10:16:57 +02:00
|
|
|
"fmt"
|
2016-08-28 19:21:57 +02:00
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"syscall"
|
2015-12-23 19:11:29 +01:00
|
|
|
"time"
|
2015-10-12 10:16:57 +02:00
|
|
|
)
|
|
|
|
|
2015-12-23 19:11:29 +01:00
|
|
|
// Instance represents a Linux VM or a remote physical machine.
|
2015-10-12 10:16:57 +02:00
|
|
|
type Instance interface {
|
2016-01-11 17:33:44 +01:00
|
|
|
// 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)
|
|
|
|
|
2015-12-23 19:11:29 +01:00
|
|
|
// 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)
|
2016-01-11 17:33:44 +01:00
|
|
|
|
2015-12-23 19:11:29 +01:00
|
|
|
// Close stops and destroys the VM.
|
|
|
|
Close()
|
2015-10-12 10:16:57 +02:00
|
|
|
}
|
|
|
|
|
2015-10-19 12:47:37 +02:00
|
|
|
type Config struct {
|
2016-01-11 17:33:44 +01:00
|
|
|
Name string
|
|
|
|
Index int
|
|
|
|
Workdir string
|
|
|
|
Bin string
|
2016-07-20 11:32:14 +02:00
|
|
|
Initrd string
|
2016-01-11 17:33:44 +01:00
|
|
|
Kernel string
|
|
|
|
Cmdline string
|
|
|
|
Image string
|
|
|
|
Sshkey string
|
2016-01-20 13:58:57 +01:00
|
|
|
Executor string
|
2016-01-11 17:33:44 +01:00
|
|
|
ConsoleDev string
|
|
|
|
Cpu int
|
|
|
|
Mem int
|
|
|
|
Debug bool
|
2015-10-19 12:47:37 +02:00
|
|
|
}
|
|
|
|
|
2015-12-23 19:11:29 +01:00
|
|
|
type ctorFunc func(cfg *Config) (Instance, error)
|
2015-10-12 10:16:57 +02:00
|
|
|
|
|
|
|
var ctors = make(map[string]ctorFunc)
|
|
|
|
|
|
|
|
func Register(typ string, ctor ctorFunc) {
|
|
|
|
ctors[typ] = ctor
|
|
|
|
}
|
|
|
|
|
2015-12-23 19:11:29 +01:00
|
|
|
// Create creates and boots a new VM instance.
|
|
|
|
func Create(typ string, cfg *Config) (Instance, error) {
|
2015-10-12 10:16:57 +02:00
|
|
|
ctor := ctors[typ]
|
|
|
|
if ctor == nil {
|
|
|
|
return nil, fmt.Errorf("unknown instance type '%v'", typ)
|
|
|
|
}
|
2015-12-23 19:11:29 +01:00
|
|
|
return ctor(cfg)
|
2015-10-12 10:16:57 +02:00
|
|
|
}
|
2015-12-23 19:11:29 +01:00
|
|
|
|
2016-08-28 19:21:57 +02:00
|
|
|
func LongPipe() (io.ReadCloser, io.WriteCloser, error) {
|
|
|
|
r, w, err := os.Pipe()
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, fmt.Errorf("failed to create pipe: %v", err)
|
|
|
|
}
|
|
|
|
for sz := 128 << 10; sz <= 2<<20; sz *= 2 {
|
|
|
|
syscall.Syscall(syscall.SYS_FCNTL, w.Fd(), syscall.F_SETPIPE_SZ, uintptr(sz))
|
|
|
|
}
|
|
|
|
return r, w, err
|
|
|
|
}
|
|
|
|
|
2016-01-19 17:17:40 +01:00
|
|
|
// FindCrash searches kernel console output for oops messages.
|
|
|
|
// Desc contains a more-or-less representative description of the first oops,
|
|
|
|
// start and end denote region of output with oops message(s).
|
|
|
|
func FindCrash(output []byte) (desc string, start int, end int, found bool) {
|
|
|
|
for pos := 0; pos < len(output); {
|
|
|
|
next := bytes.IndexByte(output[pos:], '\n')
|
|
|
|
if next != -1 {
|
|
|
|
next += pos
|
|
|
|
} else {
|
|
|
|
next = len(output)
|
|
|
|
}
|
|
|
|
for _, oops := range oopses {
|
|
|
|
match := bytes.Index(output[pos:next], oops)
|
|
|
|
if match == -1 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if !found {
|
|
|
|
found = true
|
|
|
|
start = pos
|
|
|
|
desc = string(output[pos+match : next])
|
|
|
|
if desc[len(desc)-1] == '\r' {
|
|
|
|
desc = desc[:len(desc)-1]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
end = next
|
|
|
|
}
|
|
|
|
pos = next + 1
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-12-23 19:11:29 +01:00
|
|
|
var (
|
2016-01-19 17:17:40 +01:00
|
|
|
oopses = [][]byte{
|
|
|
|
[]byte("Kernel panic"),
|
|
|
|
[]byte("BUG:"),
|
|
|
|
[]byte("kernel BUG"),
|
|
|
|
[]byte("WARNING:"),
|
|
|
|
[]byte("INFO:"),
|
|
|
|
[]byte("unable to handle"),
|
|
|
|
[]byte("Unable to handle kernel"),
|
|
|
|
[]byte("general protection fault"),
|
|
|
|
[]byte("UBSAN:"),
|
|
|
|
[]byte("unreferenced object"),
|
|
|
|
}
|
|
|
|
|
2015-12-23 19:11:29 +01:00
|
|
|
TimeoutErr = errors.New("timeout")
|
|
|
|
)
|