mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-01-28 19:29:20 +00:00
crosvm: add advisory locking for disk images
Disk images should never be mounted as writable by multiple VMs at once. Add advisory locking to prevent this. BUG=chromium:810576 TEST=run crosvm twice with same rwdisk, check that second VM fails to start Change-Id: I5e6c178515eafa570812a093449eef5a4edc1740 Reviewed-on: https://chromium-review.googlesource.com/929994 Commit-Ready: Stephen Barber <smbarber@chromium.org> Tested-by: Stephen Barber <smbarber@chromium.org> Reviewed-by: Dylan Reid <dgreid@chromium.org> Reviewed-by: Zach Reizner <zachr@chromium.org>
This commit is contained in:
parent
859b5d9d14
commit
c79de2d0b2
2 changed files with 42 additions and 0 deletions
10
src/linux.rs
10
src/linux.rs
|
@ -53,6 +53,7 @@ pub enum Error {
|
|||
DeviceJail(io_jail::Error),
|
||||
DevicePivotRoot(io_jail::Error),
|
||||
Disk(io::Error),
|
||||
DiskImageLock(sys_util::Error),
|
||||
GetWaylandGroup(sys_util::Error),
|
||||
LoadCmdline(kernel_loader::Error),
|
||||
LoadKernel(kernel_loader::Error),
|
||||
|
@ -107,6 +108,7 @@ impl fmt::Display for Error {
|
|||
&Error::DeviceJail(ref e) => write!(f, "failed to jail device: {}", e),
|
||||
&Error::DevicePivotRoot(ref e) => write!(f, "failed to pivot root device: {}", e),
|
||||
&Error::Disk(ref e) => write!(f, "failed to load disk image: {}", e),
|
||||
&Error::DiskImageLock(ref e) => write!(f, "failed to lock disk image: {:?}", e),
|
||||
&Error::GetWaylandGroup(ref e) => {
|
||||
write!(f, "could not find gid for wayland group: {:?}", e)
|
||||
}
|
||||
|
@ -303,6 +305,14 @@ fn setup_mmio_bus(cfg: &Config,
|
|||
.write(disk.writable)
|
||||
.open(&disk.path)
|
||||
.map_err(|e| Error::Disk(e))?;
|
||||
// Lock the disk image to prevent other crosvm instances from using it.
|
||||
let lock_op = if disk.writable {
|
||||
FlockOperation::LockExclusive
|
||||
} else {
|
||||
FlockOperation::LockShared
|
||||
};
|
||||
flock(&raw_image, lock_op, true).map_err(Error::DiskImageLock)?;
|
||||
|
||||
let block_box: Box<devices::virtio::VirtioDevice> = match disk.disk_type {
|
||||
DiskType::FlatFile => { // Access as a raw block device.
|
||||
Box::new(devices::virtio::Block::new(raw_image)
|
||||
|
|
|
@ -53,6 +53,7 @@ pub use guest_memory::Error as GuestMemoryError;
|
|||
pub use signalfd::Error as SignalFdError;
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::ptr;
|
||||
|
||||
use libc::{kill, syscall, sysconf, waitpid, c_long, pid_t, uid_t, gid_t, _SC_PAGESIZE,
|
||||
|
@ -102,6 +103,37 @@ pub fn chown(path: &CStr, uid: uid_t, gid: gid_t) -> Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The operation to perform with `flock`.
|
||||
pub enum FlockOperation {
|
||||
LockShared,
|
||||
LockExclusive,
|
||||
Unlock,
|
||||
}
|
||||
|
||||
/// Safe wrapper for flock(2) with the operation `op` and optionally `nonblocking`. The lock will be
|
||||
/// dropped automatically when `file` is dropped.
|
||||
#[inline(always)]
|
||||
pub fn flock(file: &AsRawFd, op: FlockOperation, nonblocking: bool) -> Result<()> {
|
||||
let mut operation = match op {
|
||||
FlockOperation::LockShared => libc::LOCK_SH,
|
||||
FlockOperation::LockExclusive => libc::LOCK_EX,
|
||||
FlockOperation::Unlock => libc::LOCK_UN,
|
||||
};
|
||||
|
||||
if nonblocking {
|
||||
operation |= libc::LOCK_NB;
|
||||
}
|
||||
|
||||
// Safe since we pass in a valid fd and flock operation, and check the return value.
|
||||
let ret = unsafe { libc::flock(file.as_raw_fd(), operation) };
|
||||
|
||||
if ret < 0 {
|
||||
errno_result()
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Reaps a child process that has terminated.
|
||||
///
|
||||
/// Returns `Ok(pid)` where `pid` is the process that was reaped or `Ok(0)` if none of the children
|
||||
|
|
Loading…
Reference in a new issue