summary refs log tree commit diff
path: root/arch
diff options
context:
space:
mode:
authorZach Reizner <zachr@google.com>2019-08-13 11:20:14 -0700
committerCommit Bot <commit-bot@chromium.org>2019-10-10 02:09:13 +0000
commita8adff0ff14f66570a3aa86f6106b55081526be1 (patch)
tree515ed01d01828a8622bac5203d508da708db5d41 /arch
parent0b6f02fea7716ec5752555ea44aafed214b58faa (diff)
downloadcrosvm-a8adff0ff14f66570a3aa86f6106b55081526be1.tar
crosvm-a8adff0ff14f66570a3aa86f6106b55081526be1.tar.gz
crosvm-a8adff0ff14f66570a3aa86f6106b55081526be1.tar.bz2
crosvm-a8adff0ff14f66570a3aa86f6106b55081526be1.tar.lz
crosvm-a8adff0ff14f66570a3aa86f6106b55081526be1.tar.xz
crosvm-a8adff0ff14f66570a3aa86f6106b55081526be1.tar.zst
crosvm-a8adff0ff14f66570a3aa86f6106b55081526be1.zip
devices: jail serial device
This change plumbs the jail throughout the arch specific device creation
process. It also adds a custom callback support for the ProxyDevice so
that the main process can interrupt the child serial process when it has
incoming bytes.

TEST=crosvm run
BUG=None

Change-Id: I6af7d2cb0acbba9bf42eaeeb294cee2bce4a1f36
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1752589
Reviewed-by: Dylan Reid <dgreid@chromium.org>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Tested-by: Zach Reizner <zachr@chromium.org>
Commit-Queue: Zach Reizner <zachr@chromium.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/src/lib.rs68
1 files changed, 52 insertions, 16 deletions
diff --git a/arch/src/lib.rs b/arch/src/lib.rs
index 28f1168..45ed247 100644
--- a/arch/src/lib.rs
+++ b/arch/src/lib.rs
@@ -16,13 +16,13 @@ use std::sync::Arc;
 use devices::virtio::VirtioDevice;
 use devices::{
     Bus, BusDevice, BusError, PciDevice, PciDeviceError, PciInterruptPin, PciRoot, ProxyDevice,
-    Serial, SerialParameters, DEFAULT_SERIAL_PARAMS, SERIAL_ADDR,
+    SerialInput, SerialParameters, DEFAULT_SERIAL_PARAMS, SERIAL_ADDR,
 };
 use io_jail::Minijail;
 use kvm::{IoeventAddress, Kvm, Vcpu, Vm};
 use resources::SystemAllocator;
 use sync::Mutex;
-use sys_util::{syslog, EventFd, GuestAddress, GuestMemory, GuestMemoryError};
+use sys_util::{pipe, poll_in, syslog, warn, EventFd, GuestAddress, GuestMemory, GuestMemoryError};
 
 pub enum VmImage {
     Kernel(File),
@@ -47,7 +47,7 @@ pub struct RunnableLinuxVm {
     pub vm: Vm,
     pub kvm: Kvm,
     pub resources: SystemAllocator,
-    pub stdio_serial: Option<Arc<Mutex<Serial>>>,
+    pub stdio_serial: Option<SerialInput>,
     pub exit_evt: EventFd,
     pub vcpus: Vec<Vcpu>,
     pub vcpu_affinity: Vec<usize>,
@@ -80,6 +80,7 @@ pub trait LinuxArch {
         components: VmComponents,
         split_irqchip: bool,
         serial_parameters: &BTreeMap<u8, SerialParameters>,
+        serial_jail: Option<Minijail>,
         create_devices: F,
     ) -> Result<RunnableLinuxVm, Self::Error>
     where
@@ -103,7 +104,9 @@ pub enum DeviceRegistrationError {
     AllocateIrq,
     /// Could not create the mmio device to wrap a VirtioDevice.
     CreateMmioDevice(sys_util::Error),
-    //  Unable to create serial device from serial parameters
+    // Unable to create a pipe.
+    CreatePipe(sys_util::Error),
+    // Unable to create serial device from serial parameters
     CreateSerialDevice(devices::SerialError),
     /// Could not create an event fd.
     EventFdCreate(sys_util::Error),
@@ -134,6 +137,7 @@ impl Display for DeviceRegistrationError {
             AllocateDeviceAddrs(e) => write!(f, "Allocating device addresses: {}", e),
             AllocateIrq => write!(f, "Allocating IRQ number"),
             CreateMmioDevice(e) => write!(f, "failed to create mmio device: {}", e),
+            CreatePipe(e) => write!(f, "failed to create pipe: {}", e),
             CreateSerialDevice(e) => write!(f, "failed to create serial device: {}", e),
             Cmdline(e) => write!(f, "unable to add device to kernel command line: {}", e),
             EventFdCreate(e) => write!(f, "failed to create eventfd: {}", e),
@@ -243,7 +247,8 @@ pub fn add_serial_devices(
     com_evt_1_3: &EventFd,
     com_evt_2_4: &EventFd,
     serial_parameters: &BTreeMap<u8, SerialParameters>,
-) -> Result<(Option<u8>, Option<Arc<Mutex<Serial>>>), DeviceRegistrationError> {
+    serial_jail: Option<Minijail>,
+) -> Result<(Option<u8>, Option<SerialInput>), DeviceRegistrationError> {
     let mut stdio_serial_num = None;
     let mut stdio_serial = None;
 
@@ -260,21 +265,52 @@ pub fn add_serial_devices(
             .get(&(x + 1))
             .unwrap_or(&DEFAULT_SERIAL_PARAMS[x as usize]);
 
-        let com = Arc::new(Mutex::new(
-            param
-                .create_serial_device(&com_evt)
-                .map_err(DeviceRegistrationError::CreateSerialDevice)?,
-        ));
-        io_bus
-            .insert(com.clone(), SERIAL_ADDR[x as usize], 0x8, false)
-            .unwrap();
-
         if param.console {
             stdio_serial_num = Some(x + 1);
         }
 
-        if param.stdin {
-            stdio_serial = Some(com.clone());
+        let mut preserved_fds = Vec::new();
+        let com = param
+            .create_serial_device(&com_evt, &mut preserved_fds)
+            .map_err(DeviceRegistrationError::CreateSerialDevice)?;
+
+        match serial_jail.as_ref() {
+            Some(jail) => {
+                let (rx, tx) = pipe(true).map_err(DeviceRegistrationError::CreatePipe)?;
+                preserved_fds.push(rx.as_raw_fd());
+                let com = Arc::new(Mutex::new(
+                    ProxyDevice::new_with_user_command(com, &jail, preserved_fds, move |serial| {
+                        let mut rx_buf = [0u8; 32];
+                        // This loop may end up stealing bytes from future user callbacks, so we
+                        // check to make sure the pipe is readable so as not to block the proxy
+                        // device's loop.
+                        while poll_in(&rx) {
+                            if let Ok(count) = (&rx).read(&mut rx_buf) {
+                                if let Err(e) = serial.queue_input_bytes(&rx_buf[..count]) {
+                                    warn!("failed to queue bytes into serial device {}: {}", x, e);
+                                }
+                            }
+                        }
+                    })
+                    .map_err(DeviceRegistrationError::ProxyDeviceCreation)?,
+                ));
+                io_bus
+                    .insert(com.clone(), SERIAL_ADDR[x as usize], 0x8, false)
+                    .unwrap();
+                if param.stdin {
+                    stdio_serial = Some(SerialInput::new_remote(tx, com));
+                }
+            }
+            None => {
+                let com = Arc::new(Mutex::new(com));
+                io_bus
+                    .insert(com.clone(), SERIAL_ADDR[x as usize], 0x8, false)
+                    .unwrap();
+
+                if param.stdin {
+                    stdio_serial = Some(SerialInput::new_local(com));
+                }
+            }
         }
     }