aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKris Alder <kalder@google.com>2022-09-30 09:18:25 -0700
committerDmitry Vyukov <dvyukov@google.com>2022-10-04 09:57:03 +0200
commitdc6152b573c88e2ebe79bea1fbabeaae39308422 (patch)
treea0ecad85b1b95dfd290ebd0a374e5e6486411eb9
parent3fe4fea88519c0b078cf12db3dffb8cd91d2fa61 (diff)
vm/cuttlefish, vm/gce: add custom commands for reading console
For Cuttlefish we want to read the console from the emulated device instead of the "host" GCE instance. This allows us to pass a custom command through to gce.Pool (and then to gce.instance) which is used instead. We also need to update runOnHost() to use osutil directly instead of delegating to gceInst.Run(), since it's called during VM creation. When setting up the VM the kernel logs don't exist yet.
-rw-r--r--vm/cuttlefish/cuttlefish.go42
-rw-r--r--vm/gce/gce.go77
2 files changed, 67 insertions, 52 deletions
diff --git a/vm/cuttlefish/cuttlefish.go b/vm/cuttlefish/cuttlefish.go
index ccea7c7e7..f6f61ee16 100644
--- a/vm/cuttlefish/cuttlefish.go
+++ b/vm/cuttlefish/cuttlefish.go
@@ -15,13 +15,15 @@ import (
"path/filepath"
"time"
- "github.com/google/syzkaller/pkg/log"
+ "github.com/google/syzkaller/pkg/osutil"
"github.com/google/syzkaller/pkg/report"
+ "github.com/google/syzkaller/vm/gce"
"github.com/google/syzkaller/vm/vmimpl"
)
const (
- deviceRoot = "/data/fuzz"
+ deviceRoot = "/data/fuzz"
+ consoleReadCmd = "tail -f cuttlefish/instances/cvd-1/kernel.log"
)
func init() {
@@ -30,16 +32,19 @@ func init() {
type Pool struct {
env *vmimpl.Env
- gcePool vmimpl.Pool
+ gcePool *gce.Pool
}
type instance struct {
+ name string
+ sshKey string
+ sshUser string
debug bool
gceInst vmimpl.Instance
}
func ctor(env *vmimpl.Env) (vmimpl.Pool, error) {
- gcePool, err := vmimpl.Types["gce"].Ctor(env)
+ gcePool, err := gce.Ctor(env, consoleReadCmd)
if err != nil {
return nil, fmt.Errorf("failed to create underlying GCE pool: %s", err)
}
@@ -63,6 +68,9 @@ func (pool *Pool) Create(workdir string, index int) (vmimpl.Instance, error) {
}
inst := &instance{
+ name: fmt.Sprintf("%v-%v", pool.env.Name, index),
+ sshKey: pool.env.SSHKey,
+ sshUser: pool.env.SSHUser,
debug: pool.env.Debug,
gceInst: gceInst,
}
@@ -94,24 +102,18 @@ func (pool *Pool) Create(workdir string, index int) (vmimpl.Instance, error) {
return inst, nil
}
-func (inst *instance) runOnHost(timeout time.Duration, cmd string) error {
- outc, errc, err := inst.gceInst.Run(timeout, nil, cmd)
- if err != nil {
- return fmt.Errorf("failed to run command: %s", err)
+func (inst *instance) sshArgs(command string) []string {
+ sshArgs := append(vmimpl.SSHArgs(inst.debug, inst.sshKey, 22), inst.sshUser+"@"+inst.name)
+ if inst.sshUser != "root" {
+ return append(sshArgs, "sudo", "bash", "-c", "'"+command+"'")
}
+ return append(sshArgs, command)
+}
- for {
- select {
- case <-vmimpl.Shutdown:
- return nil
- case err := <-errc:
- return err
- case out, ok := <-outc:
- if ok && inst.debug {
- log.Logf(1, "%s", out)
- }
- }
- }
+func (inst *instance) runOnHost(timeout time.Duration, command string) error {
+ _, err := osutil.RunCmd(timeout, "/root", "ssh", inst.sshArgs(command)...)
+
+ return err
}
func (inst *instance) Copy(hostSrc string) (string, error) {
diff --git a/vm/gce/gce.go b/vm/gce/gce.go
index ef213d12e..ba05af51b 100644
--- a/vm/gce/gce.go
+++ b/vm/gce/gce.go
@@ -49,26 +49,32 @@ type Config struct {
}
type Pool struct {
- env *vmimpl.Env
- cfg *Config
- GCE *gce.Context
+ env *vmimpl.Env
+ cfg *Config
+ GCE *gce.Context
+ consoleReadCmd string // optional: command to read non-standard kernel console
}
type instance struct {
- env *vmimpl.Env
- cfg *Config
- GCE *gce.Context
- debug bool
- name string
- ip string
- gceKey string // per-instance private ssh key associated with the instance
- sshKey string // ssh key
- sshUser string
- closed chan bool
- consolew io.WriteCloser
+ env *vmimpl.Env
+ cfg *Config
+ GCE *gce.Context
+ debug bool
+ name string
+ ip string
+ gceKey string // per-instance private ssh key associated with the instance
+ sshKey string // ssh key
+ sshUser string
+ closed chan bool
+ consolew io.WriteCloser
+ consoleReadCmd string // optional: command to read non-standard kernel console
}
func ctor(env *vmimpl.Env) (vmimpl.Pool, error) {
+ return Ctor(env, "")
+}
+
+func Ctor(env *vmimpl.Env, consoleReadCmd string) (*Pool, error) {
if env.Name == "" {
return nil, fmt.Errorf("config param name is empty (required for GCE)")
}
@@ -123,9 +129,10 @@ func ctor(env *vmimpl.Env) (vmimpl.Pool, error) {
}
}
pool := &Pool{
- cfg: cfg,
- env: env,
- GCE: GCE,
+ cfg: cfg,
+ env: env,
+ GCE: GCE,
+ consoleReadCmd: consoleReadCmd,
}
return pool, nil
}
@@ -182,16 +189,17 @@ func (pool *Pool) Create(workdir string, index int) (vmimpl.Instance, error) {
}
ok = true
inst := &instance{
- env: pool.env,
- cfg: pool.cfg,
- debug: pool.env.Debug,
- GCE: pool.GCE,
- name: name,
- ip: ip,
- gceKey: gceKey,
- sshKey: sshKey,
- sshUser: sshUser,
- closed: make(chan bool),
+ env: pool.env,
+ cfg: pool.cfg,
+ debug: pool.env.Debug,
+ GCE: pool.GCE,
+ name: name,
+ ip: ip,
+ gceKey: gceKey,
+ sshKey: sshKey,
+ sshUser: sshUser,
+ closed: make(chan bool),
+ consoleReadCmd: pool.consoleReadCmd,
}
return inst, nil
}
@@ -224,11 +232,16 @@ func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command strin
return nil, nil, err
}
- conAddr := fmt.Sprintf("%v.%v.%v.syzkaller.port=1@ssh-serialport.googleapis.com",
- inst.GCE.ProjectID, inst.GCE.ZoneID, inst.name)
- conArgs := append(vmimpl.SSHArgs(inst.debug, inst.gceKey, 9600), conAddr)
- // TODO: remove this later (see also a comment in getSerialPortOutput).
- conArgs = append(conArgs, "-o", "HostKeyAlgorithms=+ssh-rsa")
+ var conArgs []string
+ if inst.consoleReadCmd == "" {
+ conAddr := fmt.Sprintf("%v.%v.%v.syzkaller.port=1@ssh-serialport.googleapis.com",
+ inst.GCE.ProjectID, inst.GCE.ZoneID, inst.name)
+ conArgs = append(vmimpl.SSHArgs(inst.debug, inst.gceKey, 9600), conAddr)
+ // TODO: remove this later (see also a comment in getSerialPortOutput).
+ conArgs = append(conArgs, "-o", "HostKeyAlgorithms=+ssh-rsa")
+ } else {
+ conArgs = inst.sshArgs(inst.consoleReadCmd)
+ }
con := osutil.Command("ssh", conArgs...)
con.Env = []string{}
con.Stdout = conWpipe