From 54ab55f99cd593f71a9b572d23199101a48206ec Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Fri, 22 May 2020 00:34:09 +0000 Subject: crosvm: add memfd server --- Cargo.lock | 14 +++ Cargo.toml | 1 + aarch64/Cargo.toml | 1 + aarch64/src/lib.rs | 4 +- arch/Cargo.toml | 1 + arch/src/lib.rs | 24 +++++ seccomp/aarch64/memfd_server.policy | 15 ++++ seccomp/arm/memfd_server.policy | 15 ++++ seccomp/x86_64/memfd_server.policy | 15 ++++ servers/Cargo.toml | 11 +++ servers/src/jailed.rs | 142 ++++++++++++++++++++++++++++++ servers/src/lib.rs | 32 +++++++ servers/src/memfd.rs | 171 ++++++++++++++++++++++++++++++++++++ src/crosvm.rs | 2 + src/linux.rs | 67 ++++++++++++-- src/main.rs | 6 +- x86_64/Cargo.toml | 1 + x86_64/src/lib.rs | 11 ++- 18 files changed, 520 insertions(+), 13 deletions(-) create mode 100644 seccomp/aarch64/memfd_server.policy create mode 100644 seccomp/arm/memfd_server.policy create mode 100644 seccomp/x86_64/memfd_server.policy create mode 100644 servers/Cargo.toml create mode 100644 servers/src/jailed.rs create mode 100644 servers/src/lib.rs create mode 100644 servers/src/memfd.rs diff --git a/Cargo.lock b/Cargo.lock index a72324e..a1fd8e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,6 +15,7 @@ dependencies = [ "msg_socket 0.1.0", "remain 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "resources 0.1.0", + "servers 0.1.0", "sync 0.1.0", "sys_util 0.1.0", "vm_control 0.1.0", @@ -38,6 +39,7 @@ dependencies = [ "kvm 0.1.0", "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", "resources 0.1.0", + "servers 0.1.0", "sync 0.1.0", "sys_util 0.1.0", "vm_control 0.1.0", @@ -155,6 +157,7 @@ dependencies = [ "remain 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "resources 0.1.0", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "servers 0.1.0", "sync 0.1.0", "sys_util 0.1.0", "vhost 0.1.0", @@ -727,6 +730,16 @@ dependencies = [ "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "servers" +version = "0.1.0" +dependencies = [ + "io_jail 0.1.0", + "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "msg_socket 0.1.0", + "sys_util 0.1.0", +] + [[package]] name = "slab" version = "0.4.2" @@ -878,6 +891,7 @@ dependencies = [ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", "remain 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "resources 0.1.0", + "servers 0.1.0", "sync 0.1.0", "sys_util 0.1.0", "vm_control 0.1.0", diff --git a/Cargo.toml b/Cargo.toml index 2615178..f53d5c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,6 +81,7 @@ rand_ish = { path = "rand_ish" } remain = "*" resources = { path = "resources" } serde = "*" +servers = { path = "servers" } sync = { path = "sync" } sys_util = "*" vhost = { path = "vhost" } diff --git a/aarch64/Cargo.toml b/aarch64/Cargo.toml index c87c419..fcb4b30 100644 --- a/aarch64/Cargo.toml +++ b/aarch64/Cargo.toml @@ -16,6 +16,7 @@ libc = "*" msg_socket = { path = "../msg_socket" } remain = "*" resources = { path = "../resources" } +servers = { path = "../servers" } sync = { path = "../sync" } sys_util = { path = "../sys_util" } vm_control = { path = "../vm_control" } diff --git a/aarch64/src/lib.rs b/aarch64/src/lib.rs index 20ce8f8..eb254c4 100644 --- a/aarch64/src/lib.rs +++ b/aarch64/src/lib.rs @@ -12,8 +12,8 @@ use std::os::unix::io::FromRawFd; use std::sync::Arc; use arch::{ - get_serial_cmdline, GetSerialCmdlineError, RunnableLinuxVm, SerialHardware, SerialParameters, - VmComponents, VmImage, + get_serial_cmdline, jail_servers, GetSerialCmdlineError, RunnableLinuxVm, SerialHardware, + SerialParameters, ServerStub, VmComponents, VmImage, }; use devices::{Bus, BusError, MemoryParams, PciAddress, PciConfigMmio, PciDevice, PciInterruptPin}; use io_jail::Minijail; diff --git a/arch/Cargo.toml b/arch/Cargo.toml index 68b40a3..bd97262 100644 --- a/arch/Cargo.toml +++ b/arch/Cargo.toml @@ -15,3 +15,4 @@ resources = { path = "../resources" } sync = { path = "../sync" } sys_util = { path = "../sys_util" } vm_control = { path = "../vm_control" } +servers = { path = "../servers" } diff --git a/arch/src/lib.rs b/arch/src/lib.rs index 8f957a8..361e918 100644 --- a/arch/src/lib.rs +++ b/arch/src/lib.rs @@ -26,6 +26,7 @@ use devices::{ use io_jail::Minijail; use kvm::{IoeventAddress, Kvm, Vcpu, Vm}; use resources::SystemAllocator; +use servers::{JailedServer, Server}; use sync::Mutex; use sys_util::{syslog, EventFd, GuestAddress, GuestMemory, GuestMemoryError}; use vm_control::VmIrqRequestSocket; @@ -83,6 +84,7 @@ pub struct RunnableLinuxVm { pub irq_chip: Option, pub split_irqchip: Option<(Arc>, Arc>)>, pub gsi_relay: Option>, + pub servers: Vec>, pub io_bus: Bus, pub mmio_bus: Bus, pub pid_debug_label_map: BTreeMap, @@ -95,6 +97,12 @@ pub struct VirtioDeviceStub { pub jail: Option, } +/// The server and optional jail. +pub struct ServerStub { + pub server: Box, + pub jail: Option, +} + /// Trait which is implemented for each Linux Architecture in order to /// set up the memory, cpus, and system devices and to boot the kernel. pub trait LinuxArch { @@ -122,6 +130,7 @@ pub trait LinuxArch { ioapic_device_socket: VmIrqRequestSocket, serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>, serial_jail: Option, + servers: Vec, create_devices: F, ) -> Result where @@ -201,6 +210,21 @@ impl Display for DeviceRegistrationError { } } +pub fn jail_servers(servers: Vec) -> Result>, servers::ProxyError> { + servers + .into_iter() + .map(|ServerStub { server, jail }| { + if let Some(jail) = jail { + let preserved_fds = server.keep_fds(); + let jailed = JailedServer::jail(server, &jail, preserved_fds)?; + Ok(Box::new(jailed) as Box<_>) + } else { + Ok(server) + } + }) + .collect() +} + /// Creates a root PCI device for use by this Vm. pub fn generate_pci_root( devices: Vec<(Box, Option)>, diff --git a/seccomp/aarch64/memfd_server.policy b/seccomp/aarch64/memfd_server.policy new file mode 100644 index 0000000..d049d00 --- /dev/null +++ b/seccomp/aarch64/memfd_server.policy @@ -0,0 +1,15 @@ +# Copyright 2020 Alyssa Ross. All rights reserved. +# Copyright 2018 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +@include /usr/share/policy/crosvm/common_device.policy + +accept4: 1 +# F_ADD_SEALS +fcntl: arg1 == 1033 +ftruncate: 1 +memfd_create: 1 +open: return ENOENT +openat: return ENOENT +shutdown: 1 diff --git a/seccomp/arm/memfd_server.policy b/seccomp/arm/memfd_server.policy new file mode 100644 index 0000000..d049d00 --- /dev/null +++ b/seccomp/arm/memfd_server.policy @@ -0,0 +1,15 @@ +# Copyright 2020 Alyssa Ross. All rights reserved. +# Copyright 2018 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +@include /usr/share/policy/crosvm/common_device.policy + +accept4: 1 +# F_ADD_SEALS +fcntl: arg1 == 1033 +ftruncate: 1 +memfd_create: 1 +open: return ENOENT +openat: return ENOENT +shutdown: 1 diff --git a/seccomp/x86_64/memfd_server.policy b/seccomp/x86_64/memfd_server.policy new file mode 100644 index 0000000..d049d00 --- /dev/null +++ b/seccomp/x86_64/memfd_server.policy @@ -0,0 +1,15 @@ +# Copyright 2020 Alyssa Ross. All rights reserved. +# Copyright 2018 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +@include /usr/share/policy/crosvm/common_device.policy + +accept4: 1 +# F_ADD_SEALS +fcntl: arg1 == 1033 +ftruncate: 1 +memfd_create: 1 +open: return ENOENT +openat: return ENOENT +shutdown: 1 diff --git a/servers/Cargo.toml b/servers/Cargo.toml new file mode 100644 index 0000000..c42c57f --- /dev/null +++ b/servers/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "servers" +version = "0.1.0" +authors = ["Alyssa Ross"] +edition = "2018" + +[dependencies] +io_jail = { path = "../io_jail" } +libc = "*" +msg_socket = { path = "../msg_socket" } +sys_util = { path = "../sys_util" } diff --git a/servers/src/jailed.rs b/servers/src/jailed.rs new file mode 100644 index 0000000..c633efb --- /dev/null +++ b/servers/src/jailed.rs @@ -0,0 +1,142 @@ +// Copyright 2020 Alyssa Ross. All rights reserved. +// Copyright 2017 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +use std::fmt::{self, Display, Formatter}; +use std::io; +use std::os::unix::prelude::*; +use std::time::Duration; + +use io_jail::Minijail; +use libc; +use msg_socket::{MsgError, MsgOnSocket, MsgReceiver, MsgSender, MsgSocket}; +use sys_util::net::UnixSeqpacket; +use sys_util::{error, warn}; + +use crate::Server; + +#[derive(Debug)] +pub enum Error { + ForkingJail(io_jail::Error), + Io(io::Error), +} + +impl Display for Error { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + use Error::*; + match self { + ForkingJail(e) => write!(f, "failed to fork jail process: {}", e), + Io(e) => write!(f, "IO error configuring proxy server: {}", e), + } + } +} + +impl std::error::Error for Error {} + +const SOCKET_TIMEOUT_MS: u64 = 2000; + +#[derive(Copy, Clone, Debug, Eq, MsgOnSocket, PartialEq)] +enum Event { + Activate, + Shutdown, +} + +#[derive(Debug)] +pub struct JailedServer { + sock: MsgSocket, + server: S, +} + +fn recv_ack(sock: &MsgSocket<(), Event>) -> Result { + let event = sock.recv()?; + sock.send(&())?; + Ok(event) +} + +fn child_proc(sock: UnixSeqpacket, server: &mut S) -> Result<(), MsgError> { + let sock = MsgSocket::new(sock); + + if recv_ack(&sock)? == Event::Activate { + server.activate(); + + while recv_ack(&sock)? == Event::Activate { + warn!("server already activated"); + } + } + + eprintln!("Received shutdown"); + + // Event::Shutdown received. Time to stop. + Ok(()) +} + +impl JailedServer { + pub fn jail(mut server: S, jail: &Minijail, mut keep_fds: Vec) -> Result { + let (child_sock, parent_sock) = UnixSeqpacket::pair().map_err(Error::Io)?; + + keep_fds.push(child_sock.as_raw_fd()); + let pid = unsafe { jail.fork(Some(&keep_fds)) }.map_err(Error::ForkingJail)?; + + if pid == 0 { + server.on_sandboxed(); + if let Err(e) = child_proc(child_sock, &mut server) { + error!("child server process: {}", e); + } + + // We're explicitly not using std::process::exit here to avoid the cleanup of + // stdout/stderr globals. This can cause cascading panics and SIGILL if a worker + // thread attempts to log to stderr after at_exit handlers have been run. + // TODO(crbug.com/992494): Remove this once device shutdown ordering is clearly + // defined (or when corresponding code for devices has been removed). + // + // exit() is trivially safe. + // ! Never returns + unsafe { libc::exit(0) }; + } + + parent_sock + .set_write_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS))) + .map_err(Error::Io)?; + parent_sock + .set_read_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS))) + .map_err(Error::Io)?; + + Ok(Self { + server, + sock: MsgSocket::new(parent_sock), + }) + } +} + +impl JailedServer { + fn sync_send(&self, event: &Event) { + if let Err(e) = self.sock.send(event) { + error!("failed to send message to server: {}", e); + } + + if let Err(e) = self.sock.recv() { + error!("failed to receive ack from server: {}", e); + } + } +} + +impl Drop for JailedServer { + fn drop(&mut self) { + self.sync_send(&Event::Shutdown); + } +} + +impl Server for JailedServer { + fn keep_fds(&self) -> Vec { + panic!("Don't double jail servers!"); + } + + fn on_sandboxed(&mut self) { + panic!("Don't double jail servers!"); + } + + fn activate(&mut self) { + self.sync_send(&Event::Activate); + } +} diff --git a/servers/src/lib.rs b/servers/src/lib.rs new file mode 100644 index 0000000..5c174f9 --- /dev/null +++ b/servers/src/lib.rs @@ -0,0 +1,32 @@ +// Copyright 2020 Alyssa Ross. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +mod jailed; +mod memfd; + +use std::os::unix::prelude::*; + +pub use jailed::Error as ProxyError; +pub use jailed::JailedServer; +pub use memfd::MemfdServer; + +pub trait Server { + fn keep_fds(&self) -> Vec; + fn on_sandboxed(&mut self) {} + fn activate(&mut self); +} + +impl Server for Box { + fn keep_fds(&self) -> Vec { + (**self).keep_fds() + } + + fn on_sandboxed(&mut self) { + (**self).on_sandboxed() + } + + fn activate(&mut self) { + (**self).activate() + } +} diff --git a/servers/src/memfd.rs b/servers/src/memfd.rs new file mode 100644 index 0000000..ea6e148 --- /dev/null +++ b/servers/src/memfd.rs @@ -0,0 +1,171 @@ +// Copyright 2020 Alyssa Ross. All rights reserved. +// Copyright 2017 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +use std::convert::TryInto; +use std::error::Error; +use std::io::prelude::*; +use std::io::IoSlice; +use std::net::Shutdown; +use std::os::unix::net::{UnixListener, UnixStream}; +use std::os::unix::prelude::*; +use std::thread::{self, JoinHandle}; + +use sys_util::{error, EventFd, MemfdSeals, PollContext, PollToken, ScmSocket, SharedMemory}; + +use crate::Server; + +fn create_memfd(name: [u8; 224], size: u64) -> Result> { + let mut full_name: Vec = b"crosvm-guest-memfd-".to_vec(); + full_name.extend( + name.iter() + .map(|x| *x) + .take_while(|b| *b != 0 && *b != b'/'), + ); + + let size: usize = size.try_into()?; + + let mut seals = MemfdSeals::new(); + seals.set_grow_seal(); + seals.set_shrink_seal(); + seals.set_seal_seal(); + + let mut memfd = SharedMemory::named(full_name)?; + memfd.set_size(size as u64)?; + memfd.add_seals(seals)?; + + Ok(memfd) +} + +fn do_request(mut conn: UnixStream) -> Result<(), Box> { + let mut name = [0; 224]; + conn.read_exact(&mut name)?; + + let mut size = [0; 8]; + conn.read_exact(&mut size)?; + let size = u64::from_le_bytes(size); + + let _ = conn.shutdown(Shutdown::Read); + + match create_memfd(name, size) { + Ok(memfd) => conn.send_with_fd(&[IoSlice::new(&[0x00])], memfd.as_raw_fd())?, + Err(_) => conn.write(&[0x01])?, + }; + + Ok(()) +} + +fn run(wl_socket: UnixListener, kill_evt: EventFd) { + #[derive(Debug, PollToken)] + enum Token { + Socket, + Kill, + } + + let poll_ctx = + match PollContext::build_with(&[(&wl_socket, Token::Socket), (&kill_evt, Token::Kill)]) { + Ok(pc) => pc, + Err(e) => { + error!("failed creating PollContext: {}", e); + return; + } + }; + + 'poll: loop { + let events = match poll_ctx.wait() { + Ok(v) => v, + Err(e) => { + error!("failed polling for events: {}", e); + break; + } + }; + + for event in &events { + match dbg!(event.token()) { + Token::Socket => { + let conn = match wl_socket.accept() { + Ok((conn, _)) => conn, + Err(e) => { + error!("Failed to accept memfd connection: {}", e); + break 'poll; + } + }; + + if let Err(e) = do_request(conn) { + error!("Failed to service memfd request: {}", e); + break 'poll; + } + } + + Token::Kill => break 'poll, + } + } + } +} + +#[derive(Debug)] +pub struct MemfdServer { + kill_evt: Option, + worker_thread: Option>, + wl_socket: Option, +} + +impl MemfdServer { + pub fn new(wl_socket: UnixListener) -> Self { + Self { + kill_evt: None, + worker_thread: None, + wl_socket: Some(wl_socket), + } + } +} + +impl Drop for MemfdServer { + fn drop(&mut self) { + if let Some(kill_evt) = self.kill_evt.take() { + // Ignore the result because there is nothing we can do about it. + let _ = kill_evt.write(1); + } + + if let Some(worker_thread) = self.worker_thread.take() { + let _ = worker_thread.join(); + } + } +} + +impl Server for MemfdServer { + fn keep_fds(&self) -> Vec { + self.wl_socket.iter().map(AsRawFd::as_raw_fd).collect() + } + + fn activate(&mut self) { + let wl_socket = match self.wl_socket.take() { + Some(wl) => wl, + None => return, + }; + + let (self_kill_evt, kill_evt) = match EventFd::new().and_then(|e| Ok((e.try_clone()?, e))) { + Ok(v) => v, + Err(e) => { + error!("failed creating kill EventFd pair: {}", e); + return; + } + }; + self.kill_evt = Some(self_kill_evt); + + let worker_result = thread::Builder::new() + .name("memfd-server".to_string()) + .spawn(move || run(wl_socket, kill_evt)); + + match worker_result { + Err(e) => { + error!("failed to spawn memfd server worker: {}", e); + return; + } + Ok(join_handle) => { + self.worker_thread = Some(join_handle); + } + } + } +} diff --git a/src/crosvm.rs b/src/crosvm.rs index e6e7268..ab4429a 100644 --- a/src/crosvm.rs +++ b/src/crosvm.rs @@ -180,6 +180,7 @@ pub struct Config { pub vhost_net: bool, pub tap_fd: Vec, pub cid: Option, + pub wl_memfd: bool, pub wayland_socket_paths: BTreeMap, pub remote_wayland_device_socket_path: Option, pub wayland_dmabuf: bool, @@ -235,6 +236,7 @@ impl Default for Config { #[cfg(feature = "gpu")] gpu_parameters: None, software_tpm: false, + wl_memfd: false, wayland_socket_paths: BTreeMap::new(), remote_wayland_device_socket_path: None, wayland_dmabuf: false, diff --git a/src/linux.rs b/src/linux.rs index ee248a4..d5e12cd 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -5,8 +5,9 @@ use std::cmp::max; use std::collections::{BTreeMap, VecDeque}; use std::convert::TryFrom; +use std::env; use std::error::Error as StdError; -use std::ffi::CStr; +use std::ffi::{CStr, OsString}; use std::fmt::{self, Display}; use std::fs::{File, OpenOptions}; use std::io::{self, stdin, Read}; @@ -16,8 +17,9 @@ use std::net::Ipv4Addr; use std::num::NonZeroU8; use std::num::ParseIntError; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use std::os::unix::net::UnixStream; +use std::os::unix::net::{UnixListener, UnixStream}; use std::path::{Path, PathBuf}; +use std::process; use std::ptr; use std::str; use std::sync::{Arc, Barrier}; @@ -42,6 +44,7 @@ use msg_socket::{MsgError, MsgReceiver, MsgResult, MsgSender, MsgSocket}; use net_util::{Error as NetError, MacAddress, Tap}; use remain::sorted; use resources::{Alloc, MmioType, SystemAllocator}; +use servers::MemfdServer; use sync::{Condvar, Mutex}; use sys_util::net::{UnixSeqpacket, UnixSeqpacketListener, UnlinkUnixSeqpacketListener}; @@ -63,8 +66,8 @@ use vm_control::{ use crate::{Config, DiskOption, Executable, SharedDir, SharedDirKind, TouchDeviceOption}; use arch::{ - self, LinuxArch, RunnableLinuxVm, SerialHardware, SerialParameters, VirtioDeviceStub, - VmComponents, VmImage, + self, LinuxArch, RunnableLinuxVm, SerialHardware, SerialParameters, ServerStub, + VirtioDeviceStub, VmComponents, VmImage, }; #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] @@ -407,6 +410,16 @@ fn simple_jail(cfg: &Config, policy: &str) -> Result> { } type DeviceResult = std::result::Result; +type ServerResult = std::result::Result; + +fn create_memfd_server(cfg: &Config, memfd_socket_path: &Path) -> ServerResult { + let sock = UnixListener::bind(&memfd_socket_path).map_err(Error::CreateSocket)?; + let server = MemfdServer::new(sock); + Ok(ServerStub { + server: Box::new(server), + jail: simple_jail(&cfg, "memfd_server")?, + }) +} fn create_block_device( cfg: &Config, @@ -461,7 +474,6 @@ fn create_rng_device(cfg: &Config) -> DeviceResult { fn create_tpm_device(cfg: &Config) -> DeviceResult { use std::ffi::CString; use std::fs; - use std::process; use sys_util::chown; let tpm_storage: PathBuf; @@ -756,12 +768,18 @@ fn create_gpu_device( fn create_wayland_device( cfg: &Config, + memfd_socket_path: Option<&Path>, vm_socket: VmMemoryControlRequestSocket, resource_bridge: Option, memory_params: MemoryParams, ) -> DeviceResult { - let wayland_socket_dirs = cfg - .wayland_socket_paths + let mut wayland_socket_paths = cfg.wayland_socket_paths.clone(); + + if let Some(memfd_socket_path) = memfd_socket_path { + wayland_socket_paths.insert("__crosvm_memfd".to_string(), memfd_socket_path.into()); + } + + let wayland_socket_dirs = wayland_socket_paths .iter() .map(|(_name, path)| path.parent()) .collect::>>() @@ -778,7 +796,7 @@ fn create_wayland_device( None => Box::new( virtio::Wl::new(Params { - wayland_paths: cfg.wayland_socket_paths.clone(), + wayland_paths: wayland_socket_paths.clone(), vm_socket, resource_bridge, }) @@ -1076,6 +1094,7 @@ fn create_virtio_devices( vm: &mut Vm, resources: &mut SystemAllocator, _exit_evt: &EventFd, + memfd_socket_path: Option<&Path>, wayland_device_control_socket: VmMemoryControlRequestSocket, gpu_device_control_socket: VmMemoryControlRequestSocket, balloon_device_control_socket: BalloonControlResponseSocket, @@ -1171,6 +1190,7 @@ fn create_virtio_devices( devs.push(create_wayland_device( cfg, + memfd_socket_path, wayland_device_control_socket, wl_resource_bridge, mem_params, @@ -1279,6 +1299,7 @@ fn create_devices( vm: &mut Vm, resources: &mut SystemAllocator, exit_evt: &EventFd, + memfd_socket_path: Option<&Path>, control_sockets: &mut Vec, wayland_device_control_socket: VmMemoryControlRequestSocket, gpu_device_control_socket: VmMemoryControlRequestSocket, @@ -1294,6 +1315,7 @@ fn create_devices( vm, resources, exit_evt, + memfd_socket_path, wayland_device_control_socket, gpu_device_control_socket, balloon_device_control_socket, @@ -1830,6 +1852,29 @@ pub fn run_config(cfg: Config) -> Result<()> { msg_socket::pair::().map_err(Error::CreateSocket)?; control_sockets.push(TaggedControlSocket::VmIrq(ioapic_host_socket)); + let mut servers = vec![]; + let mut memfd_socket_path = None; + + if cfg.wl_memfd { + let mut sock_name = OsString::from("crosvm-"); + sock_name.push(process::id().to_string()); + sock_name.push("-memfd.sock"); + + memfd_socket_path = Some( + [ + env::var_os("XDG_RUNTIME_DIR").expect("XDG_RUNTIME_DIR not set"), + sock_name, + ] + .iter() + .collect::(), + ); + + servers.push(create_memfd_server( + &cfg, + memfd_socket_path.as_ref().unwrap(), + )?); + } + let sandbox = cfg.sandbox; let linux = Arch::build_vm( components, @@ -1837,6 +1882,7 @@ pub fn run_config(cfg: Config) -> Result<()> { ioapic_device_control_socket, &cfg.serial_parameters, simple_jail(&cfg, "serial")?, + servers, |mem, mem_params, vm, sys_allocator, exit_evt| { create_devices( &cfg, @@ -1845,6 +1891,7 @@ pub fn run_config(cfg: Config) -> Result<()> { vm, sys_allocator, exit_evt, + memfd_socket_path.as_ref().map(Path::new), &mut control_sockets, wayland_device_control_socket, gpu_device_control_socket, @@ -1952,6 +1999,10 @@ fn run_control( drop_capabilities().map_err(Error::DropCapabilities)?; } + for server in &mut linux.servers { + server.activate(); + } + let mut vcpu_handles = Vec::with_capacity(linux.vcpus.len()); let vcpu_thread_barrier = Arc::new(Barrier::new(linux.vcpus.len() + 1)); let run_mode_arc = Arc::new(VcpuRunMode::default()); diff --git a/src/main.rs b/src/main.rs index 7ea2e01..87ecdb6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -829,7 +829,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: })?, ) } - + "wl-memfd" => cfg.wl_memfd = true, "wayland-sock" => { let mut components = value.unwrap().split(','); let path = @@ -1469,6 +1469,10 @@ Number of virtio-net virtual queue pairs. (default: 1) ", ), + Argument::flag( + "wl-memfd", + "Enable support for requesting memfds over virtio_wl.", + ), Argument::value( "wayland-sock", "PATH[,name=NAME]", diff --git a/x86_64/Cargo.toml b/x86_64/Cargo.toml index 49ef53f..6f6bfaf 100644 --- a/x86_64/Cargo.toml +++ b/x86_64/Cargo.toml @@ -17,6 +17,7 @@ kvm_sys = { path = "../kvm_sys" } libc = "*" remain = "*" resources = { path = "../resources" } +servers = { path = "../servers" } sync = { path = "../sync" } sys_util = { path = "../sys_util" } acpi_tables = {path = "../acpi_tables" } diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs index 3aff53d..7c136ec 100644 --- a/x86_64/src/lib.rs +++ b/x86_64/src/lib.rs @@ -57,8 +57,8 @@ use crate::bootparam::boot_params; use acpi_tables::aml::Aml; use acpi_tables::sdt::SDT; use arch::{ - get_serial_cmdline, GetSerialCmdlineError, RunnableLinuxVm, SerialHardware, SerialParameters, - VmComponents, VmImage, + get_serial_cmdline, jail_servers, GetSerialCmdlineError, RunnableLinuxVm, SerialHardware, + SerialParameters, ServerStub, VmComponents, VmImage, }; use devices::split_irqchip_common::GsiRelay; use devices::{ @@ -97,6 +97,7 @@ pub enum Error { E820Configuration, EnableSplitIrqchip(sys_util::Error), GetSerialCmdline(GetSerialCmdlineError), + JailServers(servers::ProxyError), KernelOffsetPastEnd, LoadBios(io::Error), LoadBzImage(bzimage::Error), @@ -148,6 +149,7 @@ impl Display for Error { E820Configuration => write!(f, "invalid e820 setup params"), EnableSplitIrqchip(e) => write!(f, "failed to enable split irqchip: {}", e), GetSerialCmdline(e) => write!(f, "failed to get serial cmdline: {}", e), + JailServers(e) => write!(f, "failed to jail servers: {}", e), KernelOffsetPastEnd => write!(f, "the kernel extends past the end of RAM"), LoadBios(e) => write!(f, "error loading bios: {}", e), LoadBzImage(e) => write!(f, "error loading kernel bzImage: {}", e), @@ -347,6 +349,7 @@ impl arch::LinuxArch for X8664arch { ioapic_device_socket: VmIrqRequestSocket, serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>, serial_jail: Option, + servers: Vec, create_devices: F, ) -> Result where @@ -408,6 +411,9 @@ impl arch::LinuxArch for X8664arch { } else { (None, None) }; + + let servers = jail_servers(servers).map_err(Error::JailServers)?; + let pci_devices = create_devices(&mem, mem_params, &mut vm, &mut resources, &exit_evt) .map_err(|e| Error::CreateDevices(Box::new(e)))?; let (pci, pci_irqs, pid_debug_label_map) = arch::generate_pci_root( @@ -532,6 +538,7 @@ impl arch::LinuxArch for X8664arch { irq_chip, split_irqchip, gsi_relay, + servers, io_bus, mmio_bus, pid_debug_label_map, -- cgit 1.4.1