summary refs log tree commit diff
path: root/sys_util/src/lib.rs
diff options
context:
space:
mode:
authorStephen Barber <smbarber@chromium.org>2018-02-21 14:17:27 -0800
committerchrome-bot <chrome-bot@chromium.org>2018-02-21 22:26:53 -0800
commitc79de2d0b2b75c18adf1b9f1779a6b482247531e (patch)
treea77ca1e92c813453ebe03f6d26d47be0533d858f /sys_util/src/lib.rs
parent859b5d9d147fc59e42d3eeccd9b7bc7f857a2b01 (diff)
downloadcrosvm-c79de2d0b2b75c18adf1b9f1779a6b482247531e.tar
crosvm-c79de2d0b2b75c18adf1b9f1779a6b482247531e.tar.gz
crosvm-c79de2d0b2b75c18adf1b9f1779a6b482247531e.tar.bz2
crosvm-c79de2d0b2b75c18adf1b9f1779a6b482247531e.tar.lz
crosvm-c79de2d0b2b75c18adf1b9f1779a6b482247531e.tar.xz
crosvm-c79de2d0b2b75c18adf1b9f1779a6b482247531e.tar.zst
crosvm-c79de2d0b2b75c18adf1b9f1779a6b482247531e.zip
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>
Diffstat (limited to 'sys_util/src/lib.rs')
-rw-r--r--sys_util/src/lib.rs32
1 files changed, 32 insertions, 0 deletions
diff --git a/sys_util/src/lib.rs b/sys_util/src/lib.rs
index 7f9f034..e4547bb 100644
--- a/sys_util/src/lib.rs
+++ b/sys_util/src/lib.rs
@@ -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