tree: 1950c815dd750ed3d028a9ce36e62b7adc4f61ce [path history] [tgz]
  3. scoped_termios.h
  5. utils.h
  8. vsh_client.h
  11. vsh_forwarder.h

vsh - Vsock SHell

Warning: This document is old & has moved. Please update any links:

vsh is a remote shell that operates over vsock. Think of ssh, but replace the first ‘s’ with a ‘v’.

Why vsh?

SSH is the de-facto standard for getting a shell on a remote machine over a network. This makes a lot of sense for a machine under your desk or a VM in the cloud.

The most critical features SSH provides are:

  • Host authentication ensures you're talking to the right machine.
  • User authentication ensures only authorized users can sign in, and only as themselves.
  • Encryption prevents parties between the two machines snooping on your traffic.

vsh is focused on one use case only: connect to a VM on the same machine. This lets us simplify the requirements substantially.

  • Host authentication is provided by vsock. Unlike IP, a VM cannot spoof its vsock context id. vsock is machine-local, so there is no concern with MitM attacks.

  • User authentication is not required. vsh is used exclusively from host to guest, and the host is always considered more privileged.

  • Encryption isn't necessary since vsock cannot be routed, and the traffic will transit directly between host and guest memory. Without a host kernel exploit, a VM cannot observe traffic intended for another VM.

Without the need for any encryption, vsh is simple to set up, and easily integrated into a VM project. There's no need to have the guest OS configure a network, since vsock does not require guest-side configuration.

NOTE: Although the guest-side vshd does not authenticate users, it does limit which user a shell can be launched with. For example, Crostini's termina VM will only allow logging in as chronos. Developers must build a test image of termina to allow logging in as root.


vsh can:

  • Run both interactive shells (like bash), as well as one-shot commands.

  • Detect interactive vs non-interactive usage. This allows piping binary data through vsh without triggering terminal escape codes, as well as using vsh to pipe stdout and stderr output separately.

  • Forward exit status from the guest-side process.

  • Forward certain signals. Sending SIGHUP, SIGINT, SIGQUIT, or SIGTERM will forward the signal to the remote process. This is useful in non-interactive environments such as Tast to force the guest-side process to exit cleanly.

Usage examples

Launches a shell on the VM with vsock cid 3. This will work even with a manually launched crosvm instance, as long as the guest is running vshd.

(device) # vsh --cid=3

Launches a shell on the VM named foo. Names are managed by vm_concierge, so this VM must have been started through the vm_concierge API. The $CROS_USER_ID_HASH variable is only set for crosh-spawned shells. The included one-liner can set it for you.

(device) # export CROS_USER_ID_HASH="$(cryptohome --action=status | \
                                       python3 -c 'import sys, json; \

(device) # vsh --vm_name=foo --owner_id="${CROS_USER_ID_HASH}"

Launches a root shell on the VM named foo. This may require that the VM is running a developer-built test image.

(device) # vsh --vm_name=foo --owner_id="${CROS_USER_ID_HASH}" --user=root

Runs lxc list in the termina VM with required environment variables set.

(device) # vsh --vm_name=termina \
               --owner_id="${CROS_USER_ID_HASH}" \
               -- \
               LXD_DIR=/mnt/stateful/lxd \
               LXD_CONF=/mnt/stateful/lxd_conf \
               lxc list

Writes a host file foo to /bar in the crostini container penguin.

(device) # cat foo | vsh --vm_name=termina \
                         --owner_id="${CROS_USER_ID_HASH}" \
                         --target_container=penguin \
                         -- \
                         sh -c "cat - > /bar"

Writes a file /foo from crostini container penguin to bar on the host.

(device) # vsh --vm_name=termina \
               --owner_id="${CROS_USER_ID_HASH}" \
               --target_container=penguin \
               -- \
               cat /foo > bar