summary refs log tree commit diff
path: root/src/main.rs
diff options
context:
space:
mode:
authorDylan Reid <dgreid@chromium.org>2017-05-12 16:15:53 -0700
committerchrome-bot <chrome-bot@chromium.org>2017-07-06 21:13:55 -0700
commit61edbbff532fd25951f58a10195e96220d43399a (patch)
tree07fa20a0fa34ec5cb7abc14b64d0edc6d5eaa939 /src/main.rs
parentf2164a18bf9e58051e5b8bf4c063c19297a77878 (diff)
downloadcrosvm-61edbbff532fd25951f58a10195e96220d43399a.tar
crosvm-61edbbff532fd25951f58a10195e96220d43399a.tar.gz
crosvm-61edbbff532fd25951f58a10195e96220d43399a.tar.bz2
crosvm-61edbbff532fd25951f58a10195e96220d43399a.tar.lz
crosvm-61edbbff532fd25951f58a10195e96220d43399a.tar.xz
crosvm-61edbbff532fd25951f58a10195e96220d43399a.tar.zst
crosvm-61edbbff532fd25951f58a10195e96220d43399a.zip
crosvm: Put block device process in a minijail
Run with the new seccomp filter and drop all capabilities.  In addition enter a
new user, mount, network, and ipc namespace.  Leave the mount namespace empty
after pivot-rooting to an empty directory.

Change-Id: Iee583cf260ede8ca13f005836684eb80c2c3ac3e
Signed-off-by: Dylan Reid <dgreid@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/515603
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs52
1 files changed, 49 insertions, 3 deletions
diff --git a/src/main.rs b/src/main.rs
index 1e1d601..603369d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -6,22 +6,27 @@
 
 extern crate clap;
 extern crate libc;
+extern crate io_jail;
 extern crate kvm;
 extern crate x86_64;
 extern crate kernel_loader;
 extern crate byteorder;
 #[macro_use] extern crate sys_util;
+extern crate syscall_defines;
 
 use std::ffi::{CString, CStr};
 use std::fmt;
 use std::fs::File;
 use std::io::{stdin, stdout};
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::path::Path;
 use std::string::String;
 use std::sync::{Arc, Mutex, Barrier};
 use std::thread::{spawn, JoinHandle};
 
 use clap::{Arg, App, SubCommand};
 
+use io_jail::Minijail;
 use kvm::*;
 use sys_util::{GuestAddress, GuestMemory, EventFd, Terminal, Poller, Pollable,
                register_signal_handler, Killable};
@@ -36,6 +41,8 @@ enum Error {
     Socket(std::io::Error),
     Disk(std::io::Error),
     BlockDeviceNew(sys_util::Error),
+    BlockDeviceJail(io_jail::Error),
+    BlockDevicePivotRoot(io_jail::Error),
     Cmdline(kernel_cmdline::Error),
     ProxyDeviceCreation(std::io::Error),
     RegisterIoevent(sys_util::Error),
@@ -73,6 +80,10 @@ impl fmt::Display for Error {
             &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),
+            &Error::BlockDeviceJail(ref e) => write!(f, "failed to jail block device: {:?}", e),
+            &Error::BlockDevicePivotRoot(ref e) => {
+                write!(f, "failed to pivot root block device: {:?}", e)
+            }
             &Error::Cmdline(ref e) => write!(f, "the given kernel command line was invalid: {}", e),
             &Error::ProxyDeviceCreation(ref e) => write!(f, "failed to create proxy device: {}", e),
             &Error::RegisterIoevent(ref e) => write!(f, "error registering ioevent: {:?}", e),
@@ -110,6 +121,26 @@ const KERNEL_START_OFFSET: usize = 0x200000;
 const CMDLINE_OFFSET: usize = 0x20000;
 const CMDLINE_MAX_SIZE: usize = KERNEL_START_OFFSET - CMDLINE_OFFSET;
 
+fn create_block_device_jail() -> Result<Minijail> {
+    // All child jails run in a new user namespace without any users mapped,
+    // they run as nobody unless otherwise configured.
+    let mut j = Minijail::new().map_err(|e| Error::BlockDeviceJail(e))?;
+    // Don't need any capabilities.
+    j.use_caps(0);
+    // Create a new mount namespace with an empty root FS.
+    j.namespace_vfs();
+    j.enter_pivot_root(Path::new("/run/asdf"))
+        .map_err(|e| Error::BlockDevicePivotRoot(e))?;
+    // Run in an empty network namespace.
+    j.namespace_net();
+    // Apply the block device seccomp policy.
+    j.no_new_privs();
+    j.parse_seccomp_filters(Path::new("block_device.policy"))
+        .map_err(|e| Error::BlockDeviceJail(e))?;
+    j.use_seccomp_filter();
+    Ok(j)
+}
+
 fn run_config(cfg: Config) -> Result<()> {
     let socket = if let Some(ref socket_path) = cfg.socket_path {
         Some(ControlSocketRecv::new(socket_path)
@@ -136,7 +167,11 @@ fn run_config(cfg: Config) -> Result<()> {
     let mut irq: u32 = 5;
 
     if let Some(ref disk_path) = cfg.disk_path {
+        // List of FDs to keep open in the child after it forks.
+        let mut keep_fds: Vec<RawFd> = Vec::new();
+
         let disk_image = File::open(disk_path).map_err(|e| Error::Disk(e))?;
+        keep_fds.push(disk_image.as_raw_fd());
 
         let block_box = Box::new(hw::virtio::Block::new(disk_image)
                                      .map_err(|e| Error::BlockDeviceNew(e))?);
@@ -144,16 +179,27 @@ fn run_config(cfg: Config) -> Result<()> {
         for (i, queue_evt) in block_mmio.queue_evts().iter().enumerate() {
             let io_addr = IoeventAddress::Mmio(mmio_base + hw::virtio::NOITFY_REG_OFFSET as u64);
             vm_requests.push(VmRequest::RegisterIoevent(queue_evt.try_clone()?, io_addr, i as u32));
+            keep_fds.push(queue_evt.as_raw_fd());
         }
 
         if let Some(interrupt_evt) = block_mmio.interrupt_evt() {
             vm_requests.push(VmRequest::RegisterIrqfd(interrupt_evt.try_clone()?, irq));
+            keep_fds.push(interrupt_evt.as_raw_fd());
         }
 
         if cfg.multiprocess {
-            bus.insert(Arc::new(Mutex::new(hw::ProxyDevice::new(block_mmio).unwrap())),
-                        mmio_base,
-                        mmio_len)
+            let jail = create_block_device_jail()?;
+            let proxy_dev = hw::ProxyDevice::new(block_mmio, move |keep_pipe| {
+                keep_fds.push(keep_pipe.as_raw_fd());
+                // Need to panic here as there isn't a way to recover from a
+                // partly-jailed process.
+                unsafe {
+                    // This is OK as we have whitelisted all the FDs we need open.
+                    jail.enter(Some(&keep_fds)).unwrap();
+                }
+            })
+                    .map_err(|e| Error::ProxyDeviceCreation(e))?;
+            bus.insert(Arc::new(Mutex::new(proxy_dev)), mmio_base, mmio_len)
                 .unwrap();
         } else {
             bus.insert(Arc::new(Mutex::new(block_mmio)), mmio_base, mmio_len)