summary refs log tree commit diff
path: root/src/main.rs
diff options
context:
space:
mode:
authorZach Reizner <zachr@google.com>2017-06-30 15:46:14 -0700
committerchrome-bot <chrome-bot@chromium.org>2017-09-08 17:35:58 -0700
commit2bcf05b2afbcbe1287583a229dbb3e5b6c78aa8c (patch)
treef5fbad7c0b88a8f8727d92692ac996b62647c24c /src/main.rs
parent22175fe3681d7102bb62fb89b0bb0cb317973bcc (diff)
downloadcrosvm-2bcf05b2afbcbe1287583a229dbb3e5b6c78aa8c.tar
crosvm-2bcf05b2afbcbe1287583a229dbb3e5b6c78aa8c.tar.gz
crosvm-2bcf05b2afbcbe1287583a229dbb3e5b6c78aa8c.tar.bz2
crosvm-2bcf05b2afbcbe1287583a229dbb3e5b6c78aa8c.tar.lz
crosvm-2bcf05b2afbcbe1287583a229dbb3e5b6c78aa8c.tar.xz
crosvm-2bcf05b2afbcbe1287583a229dbb3e5b6c78aa8c.tar.zst
crosvm-2bcf05b2afbcbe1287583a229dbb3e5b6c78aa8c.zip
crosvm: add virtio wayland device
This adds the virtio wayland device which is activated by default. The wayland
device needs the XDG_RUNTIME_DIR env variable to be set and a running wayland
compositor to connect to in that directory.

TEST=crosvm run <other args>
BUG=chromium:738638

Change-Id: Iaa417c6bb74739896042318451b4befcac0c1d0e
Reviewed-on: https://chromium-review.googlesource.com/559860
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs64
1 files changed, 61 insertions, 3 deletions
diff --git a/src/main.rs b/src/main.rs
index 8f53e1b..273b4bb 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -25,7 +25,8 @@ pub mod kernel_cmdline;
 pub mod vm_control;
 pub mod device_manager;
 
-use std::ffi::{CString, CStr};
+use std::env::var_os;
+use std::ffi::{OsString, CString, CStr};
 use std::fmt;
 use std::fs::{File, OpenOptions, remove_file};
 use std::io::{stdin, stdout};
@@ -41,8 +42,9 @@ use std::time::Duration;
 use io_jail::Minijail;
 use kvm::*;
 use sys_util::{GuestAddress, GuestMemory, EventFd, TempDir, Terminal, Poller, Pollable, Scm,
-               register_signal_handler, Killable, SignalFd, getpid, kill_process_group, reap_child,
-               syslog};
+               register_signal_handler, Killable, SignalFd, geteuid, getegid, getpid,
+               kill_process_group, reap_child, syslog};
+
 
 use argument::{Argument, set_arguments, print_help};
 use device_manager::*;
@@ -50,6 +52,7 @@ use vm_control::{VmRequest, VmResponse};
 
 enum Error {
     OpenKernel(PathBuf, std::io::Error),
+    EnvVar(&'static str),
     Socket(std::io::Error),
     Disk(std::io::Error),
     BlockDeviceNew(sys_util::Error),
@@ -61,7 +64,9 @@ enum Error {
     DevicePivotRoot(io_jail::Error),
     RegisterBlock(device_manager::Error),
     RegisterNet(device_manager::Error),
+    RegisterWayland(device_manager::Error),
     Cmdline(kernel_cmdline::Error),
+    MissingWayland(PathBuf),
     RegisterIrqfd(sys_util::Error),
     RegisterRng(device_manager::Error),
     RngDeviceNew(hw::virtio::RngError),
@@ -100,6 +105,7 @@ impl fmt::Display for Error {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
             &Error::OpenKernel(ref p, ref e) => write!(f, "failed to open kernel image {:?}: {}", p, e),
+            &Error::EnvVar(key) => write!(f, "missing enviroment variable: {}", key),
             &Error::Socket(ref e) => write!(f, "failed to create socket: {}", e),
             &Error::Disk(ref e) => write!(f, "failed to load disk image: {}", e),
             &Error::BlockDeviceNew(ref e) => write!(f, "failed to create block device: {:?}", e),
@@ -120,7 +126,9 @@ impl fmt::Display for Error {
             &Error::RngDeviceRootSetup(ref e) => {
                 write!(f, "failed to create root directory for a rng device: {:?}", e)
             }
+            &Error::RegisterWayland(ref e) => write!(f, "error registering wayland device: {}", e),
             &Error::Cmdline(ref e) => write!(f, "the given kernel command line was invalid: {}", e),
+            &Error::MissingWayland(ref p) => write!(f, "wayland socket does not exist: {:?}", p),
             &Error::RegisterIrqfd(ref e) => write!(f, "error registering irqfd: {:?}", e),
             &Error::KernelLoader(ref e) => write!(f, "error loading kernel: {:?}", e),
             #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
@@ -155,6 +163,13 @@ impl Drop for UnlinkUnixDatagram {
     }
 }
 
+fn env_var(key: &'static str) -> Result<OsString> {
+    match var_os(key) {
+        Some(v) => Ok(v),
+        None => Err(Error::EnvVar(key))
+    }
+}
+
 struct DiskOption {
     path: PathBuf,
     writable: bool,
@@ -171,6 +186,7 @@ struct Config {
     netmask: Option<net::Ipv4Addr>,
     mac_address: Option<String>,
     vhost_net: bool,
+    disable_wayland: bool,
     socket_path: Option<PathBuf>,
     multiprocess: bool,
     warn_unknown_ports: bool,
@@ -329,6 +345,44 @@ fn run_config(cfg: Config) -> Result<()> {
         }
     }
 
+    let wl_root = TempDir::new(&PathBuf::from("/tmp/wl_root"))?;
+    if !cfg.disable_wayland {
+        match env_var("XDG_RUNTIME_DIR") {
+            Ok(p) => {
+                let jailed_wayland_path = Path::new("/wayland-0");
+                let wayland_path = Path::new(&p).join("wayland-0");
+                if !wayland_path.exists() {
+                    return Err(Error::MissingWayland(wayland_path));
+                }
+
+                let (host_socket, device_socket) = UnixDatagram::pair().map_err(Error::Socket)?;
+                control_sockets.push(UnlinkUnixDatagram(host_socket));
+                let wl_box = Box::new(hw::virtio::Wl::new(if cfg.multiprocess {
+                        &jailed_wayland_path
+                    } else {
+                        wayland_path.as_path()
+                    },
+                    device_socket)?);
+
+                let jail = if cfg.multiprocess {
+                    let wl_root_path = wl_root.as_path().unwrap(); // Won't fail if new succeeded.
+                    let mut jail = create_base_minijail(wl_root_path, Path::new("wl_device.policy"))?;
+                    // Map the jail's root uid/gid to the main processes effective uid/gid so that
+                    // the jailed device can access the wayland-0 socket with the same credentials
+                    // as the main process.
+                    jail.uidmap(&format!("0 {} 1", geteuid()));
+                    jail.gidmap(&format!("0 {} 1", getegid()));
+                    jail.mount_bind(wayland_path.as_path(), jailed_wayland_path, true).unwrap();
+                    Some(jail)
+                } else {
+                    None
+                };
+                device_manager.register_mmio(wl_box, jail, &mut cmdline).map_err(Error::RegisterWayland)?;
+            }
+            _ => warn!("missing environment variable \"XDG_RUNTIME_DIR\" required to activate virtio wayland device"),
+        }
+    }
+
     if !cfg.params.is_empty() {
         cmdline
             .insert_str(cfg.params)
@@ -780,6 +834,9 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument::
             }
             cfg.mac_address = Some(value.unwrap().to_owned());
         }
+        "no-wl" => {
+            cfg.disable_wayland = true;
+        }
         "socket" => {
             if cfg.socket_path.is_some() {
                 return Err(argument::Error::TooManyArguments("`socket` already given".to_owned()));
@@ -829,6 +886,7 @@ fn run_vm(args: std::env::Args) {
                           "IP address to assign to host tap interface."),
           Argument::value("netmask", "NETMASK", "Netmask for VM subnet."),
           Argument::value("mac", "MAC", "MAC address for VM."),
+          Argument::flag("no-wl", "Disables the virtio wayland device."),
           Argument::short_value('s',
                                 "socket",
                                 "PATH",