From 61e34331c2f46e2bff31097e5aa29beb9a30817a Mon Sep 17 00:00:00 2001 From: Eryu Guan Date: Wed, 25 Mar 2020 18:04:39 +0800 Subject: [PATCH] virtio-fs: validate request len in fs_slave_io() We made sure gpa is in cache range, but not the end addr of request, which is (gpa + len). If the end addr of request is beyond dax cache window, vmm would corrupt guest memory or crash. Fix it by making sure end addr of request is within cache range as well. And while we're at it, return EFAULT if the request is out of range, as write(2)/read(2) returns EFAULT when buffer is outside accessible address space. Signed-off-by: Eryu Guan --- vm-virtio/src/vhost_user/fs.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/vm-virtio/src/vhost_user/fs.rs b/vm-virtio/src/vhost_user/fs.rs index e430eefa2..ae7d5db8e 100644 --- a/vm-virtio/src/vhost_user/fs.rs +++ b/vm-virtio/src/vhost_user/fs.rs @@ -161,20 +161,21 @@ impl VhostUserMasterReqHandler for SlaveReqHandler { let mut foffset = fs.fd_offset[i]; let mut len = fs.len[i] as usize; let gpa = fs.cache_offset[i]; - if gpa < self.cache_offset.raw_value() - || gpa >= self.cache_offset.raw_value() + self.cache_size - { - return Err(io::Error::new( - io::ErrorKind::Other, - "gpa is out of cache range", - )); - } + let cache_end = self.cache_offset.raw_value() + self.cache_size; + let efault = libc::EFAULT; let offset = gpa .checked_sub(self.cache_offset.raw_value()) - .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "gpa is out of cache range"))?; - let mut ptr = self.mmap_cache_addr + offset; + .ok_or_else(|| io::Error::from_raw_os_error(efault))?; + let end = gpa + .checked_add(fs.len[i]) + .ok_or_else(|| io::Error::from_raw_os_error(efault))?; + if gpa < self.cache_offset.raw_value() || gpa >= cache_end || end >= cache_end { + return Err(io::Error::from_raw_os_error(efault)); + } + + let mut ptr = self.mmap_cache_addr + offset; while len > 0 { let ret = if (fs.flags[i] & VhostUserFSSlaveMsgFlags::MAP_W) == VhostUserFSSlaveMsgFlags::MAP_W