summary refs log tree commit diff
path: root/devices/src/virtio/block.rs
diff options
context:
space:
mode:
authorDaniel Verkamp <dverkamp@chromium.org>2018-09-06 10:09:31 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-09-21 00:51:15 -0700
commita40cbb4a948ea826f69cb83728c31a5a253a3b1c (patch)
treecbfa493a310fbf54b98957222aa9e85ed10b56cf /devices/src/virtio/block.rs
parenta0408258e09c406324ddae0aa5c30a7b75d04e31 (diff)
downloadcrosvm-a40cbb4a948ea826f69cb83728c31a5a253a3b1c.tar
crosvm-a40cbb4a948ea826f69cb83728c31a5a253a3b1c.tar.gz
crosvm-a40cbb4a948ea826f69cb83728c31a5a253a3b1c.tar.bz2
crosvm-a40cbb4a948ea826f69cb83728c31a5a253a3b1c.tar.lz
crosvm-a40cbb4a948ea826f69cb83728c31a5a253a3b1c.tar.xz
crosvm-a40cbb4a948ea826f69cb83728c31a5a253a3b1c.tar.zst
crosvm-a40cbb4a948ea826f69cb83728c31a5a253a3b1c.zip
devices: block: enforce read-only in execute()
To fully meet the requirements laid out by the virtio specification, we
need to fail write commands for devices that expose VIRTIO_BLK_F_RO with
a specific error code of VIRTIO_BLK_S_IOERR.  Pipe the read_only status
down into the worker and the request execute function so that it can be
checked and return the correct error code.

BUG=chromium:872973
TEST=Attempt to write to read-only /dev/vda in termina

Change-Id: I98c8ad17fde497e5a529d9e65096fb4ef022fd65
Signed-off-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1211062
Reviewed-by: Stephen Barber <smbarber@chromium.org>
Diffstat (limited to 'devices/src/virtio/block.rs')
-rw-r--r--devices/src/virtio/block.rs24
1 files changed, 21 insertions, 3 deletions
diff --git a/devices/src/virtio/block.rs b/devices/src/virtio/block.rs
index 43e81e0..4b62932 100644
--- a/devices/src/virtio/block.rs
+++ b/devices/src/virtio/block.rs
@@ -111,7 +111,7 @@ unsafe impl DataInit for virtio_blk_discard_write_zeroes {}
 pub trait DiskFile: Read + Seek + Write + WriteZeroes {}
 impl<D: Read + Seek + Write + WriteZeroes> DiskFile for D {}
 
-#[derive(PartialEq)]
+#[derive(Copy, Clone, Debug, PartialEq)]
 enum RequestType {
     In,
     Out,
@@ -199,6 +199,9 @@ enum ExecuteError {
         num_sectors: u32,
         flags: u32,
     },
+    ReadOnly {
+        request_type: RequestType,
+    },
     Unsupported(u32),
 }
 
@@ -212,6 +215,7 @@ impl ExecuteError {
             &ExecuteError::TimerFd(_) => VIRTIO_BLK_S_IOERR,
             &ExecuteError::Write{ .. } => VIRTIO_BLK_S_IOERR,
             &ExecuteError::DiscardWriteZeroes{ .. } => VIRTIO_BLK_S_IOERR,
+            &ExecuteError::ReadOnly{ .. } => VIRTIO_BLK_S_IOERR,
             &ExecuteError::Unsupported(_) => VIRTIO_BLK_S_UNSUPP,
         }
     }
@@ -359,6 +363,7 @@ impl Request {
 
     fn execute<T: DiskFile>(
         &self,
+        read_only: bool,
         disk: &mut T,
         flush_timer: &mut TimerFd,
         mem: &GuestMemory,
@@ -366,6 +371,12 @@ impl Request {
         // Delay after a write when the file is auto-flushed.
         let flush_delay = Duration::from_secs(60);
 
+        if read_only && self.request_type != RequestType::In {
+            return Err(ExecuteError::ReadOnly {
+                request_type: self.request_type,
+            });
+        }
+
         disk.seek(SeekFrom::Start(self.sector << SECTOR_SHIFT))
             .map_err(|e| ExecuteError::Seek{ ioerr: e, sector: self.sector })?;
         match self.request_type {
@@ -437,6 +448,7 @@ struct Worker<T: DiskFile> {
     queues: Vec<Queue>,
     mem: GuestMemory,
     disk_image: T,
+    read_only: bool,
     interrupt_status: Arc<AtomicUsize>,
     interrupt_evt: EventFd,
 }
@@ -451,8 +463,12 @@ impl<T: DiskFile> Worker<T> {
             let len;
             match Request::parse(&avail_desc, &self.mem) {
                 Ok(request) => {
-                    let status = match request.execute(&mut self.disk_image, flush_timer, &self.mem)
-                    {
+                    let status = match request.execute(
+                        self.read_only,
+                        &mut self.disk_image,
+                        flush_timer,
+                        &self.mem,
+                    ) {
                         Ok(l) => {
                             len = l;
                             VIRTIO_BLK_S_OK
@@ -682,6 +698,7 @@ impl<T: 'static + AsRawFd + DiskFile + Send> VirtioDevice for Block<T> {
             };
         self.kill_evt = Some(self_kill_evt);
 
+        let read_only = self.read_only;
         if let Some(disk_image) = self.disk_image.take() {
             let worker_result = thread::Builder::new()
                 .name("virtio_blk".to_string())
@@ -690,6 +707,7 @@ impl<T: 'static + AsRawFd + DiskFile + Send> VirtioDevice for Block<T> {
                         queues: queues,
                         mem: mem,
                         disk_image: disk_image,
+                        read_only: read_only,
                         interrupt_status: status,
                         interrupt_evt: interrupt_evt,
                     };