vsh is a remote shell that operates over vsock. Think of ssh, but replace the first ‘s’ with a ‘v’.
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:
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'stermina
VM will only allow logging in aschronos
. Developers must build atest
image oftermina
to allow logging in asroot
.
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.
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
. Check here for an example.
(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; \ print(json.load(sys.stdin)["mounts"][0]["owner"])')" (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
First, the guest needs the vshd
executable. termina dlc is one way to get it. vshd
is contained in vm_tools.img
(device) # dlcservice_util --install --id=termina-dlc # Prints the root mount of termina-dlc, which should be `/run/imageloader/termina-dlc/package/root` (device) # dlcservice_util --list
Launch crosvm
with --cid=3
and vm_tools.img
.
(device) # crosvm run --cid=3 --disk /run/imageloader/termina-dlc/package/root/vm_tools.img ...
Then, run the following commands in guest to launch vshd
.
(guest) # mount -t proc proc /proc (guest) # mount -t sysfs sys /sys (guest) # mount -t tmpfs tmp /tmp (guest) # mount -t tmpfs run /run (guest) # mkdir /dev/pts (guest) # mount -t devpts devpts /dev/pts -o mode=0620,ptmxmode=666 (guest) # mkdir /tmp/vm_tools (guest) # mount /dev/vda /tmp/vm_tools # or vdx depending on disks available (guest) # /tmp/vm_tools/bin/vshd