diff options
| author | Kris Alder <kalder@google.com> | 2022-09-30 09:18:25 -0700 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2022-10-04 09:57:03 +0200 |
| commit | dc6152b573c88e2ebe79bea1fbabeaae39308422 (patch) | |
| tree | a0ecad85b1b95dfd290ebd0a374e5e6486411eb9 | |
| parent | 3fe4fea88519c0b078cf12db3dffb8cd91d2fa61 (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.go | 42 | ||||
| -rw-r--r-- | vm/gce/gce.go | 77 |
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 |
