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 <eguan@linux.alibaba.com>
This commit is contained in:
Eryu Guan 2020-03-25 18:04:39 +08:00 committed by Sebastien Boeuf
parent 4c9d15d44c
commit 61e34331c2

View File

@ -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