diff options
author | Dylan Reid <dgreid@chromium.org> | 2017-05-12 16:15:53 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-07-06 21:13:55 -0700 |
commit | 61edbbff532fd25951f58a10195e96220d43399a (patch) | |
tree | 07fa20a0fa34ec5cb7abc14b64d0edc6d5eaa939 /src/main.rs | |
parent | f2164a18bf9e58051e5b8bf4c063c19297a77878 (diff) | |
download | crosvm-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.rs | 52 |
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) |