vhost-kern: treat addrs in VringConfigData as HVA

The ring addresses in VringConfigData are host virtual addresses,
and the kernel vhost drivers also expect those addresses as HVA.
So it's wrong to validate/translate those addresses as GPA.

Signed-off-by: Liu Jiang <gerry@linux.alibaba.com>
This commit is contained in:
Liu Jiang 2020-12-08 23:20:44 +08:00 committed by Sergio Lopez
parent d257479a40
commit ce094b25d2
2 changed files with 71 additions and 32 deletions

View file

@ -34,6 +34,26 @@ pub struct VringConfigData {
pub log_addr: Option<u64>,
}
impl VringConfigData {
/// Check whether the log (flag, address) pair is valid.
pub fn is_log_addr_valid(&self) -> bool {
if self.flags & 0x1 != 0 && self.log_addr.is_none() {
return false;
}
true
}
/// Get the log address, default to zero if not available.
pub fn get_log_addr(&self) -> u64 {
if self.flags & 0x1 != 0 && self.log_addr.is_some() {
self.log_addr.unwrap()
} else {
0
}
}
}
/// Memory region configuration data.
#[derive(Default, Clone, Copy)]
pub struct VhostUserMemoryRegionInfo {
@ -133,3 +153,36 @@ pub trait VhostBackend: std::marker::Sized {
/// * `fd` - EventFd that will be signaled from guest.
fn set_vring_err(&mut self, queue_index: usize, fd: &EventFd) -> Result<()>;
}
#[cfg(test)]
mod tests {
use VringConfigData;
#[test]
fn test_vring_config_data() {
let mut config = VringConfigData {
queue_max_size: 0x1000,
queue_size: 0x2000,
flags: 0x0,
desc_table_addr: 0x4000,
used_ring_addr: 0x5000,
avail_ring_addr: 0x6000,
log_addr: None,
};
assert_eq!(config.is_log_addr_valid(), true);
assert_eq!(config.get_log_addr(), 0);
config.flags = 0x1;
assert_eq!(config.is_log_addr_valid(), false);
assert_eq!(config.get_log_addr(), 0);
config.log_addr = Some(0x7000);
assert_eq!(config.is_log_addr_valid(), true);
assert_eq!(config.get_log_addr(), 0x7000);
config.flags = 0x0;
assert_eq!(config.is_log_addr_valid(), true);
assert_eq!(config.get_log_addr(), 0);
}
}

View file

@ -12,7 +12,6 @@
//! control the in-kernel net, scsi, vsock vhost drivers.
use std::os::unix::io::{AsRawFd, RawFd};
use std::ptr::null;
use vm_memory::{Address, GuestAddress, GuestMemory, GuestUsize};
use vmm_sys_util::eventfd::EventFd;
@ -49,15 +48,21 @@ pub trait VhostKernBackend<'a>: AsRawFd {
/// Check whether the ring configuration is valid.
fn is_valid(&self, config_data: &VringConfigData) -> bool {
let queue_size = config_data.queue_size;
let desc_table_size = 16 * u64::from(queue_size) as GuestUsize;
let avail_ring_size = 6 + 2 * u64::from(queue_size) as GuestUsize;
let used_ring_size = 6 + 8 * u64::from(queue_size) as GuestUsize;
if queue_size > config_data.queue_max_size
|| queue_size == 0
|| (queue_size & (queue_size - 1)) != 0
{
false
} else if GuestAddress(config_data.desc_table_addr)
return false;
}
// TODO: the GuestMemory trait lacks of method to look up GPA by HVA,
// so there's no way to validate HVAs. Please extend vm-memory crate
// first.
/*
let desc_table_size = 16 * u64::from(queue_size) as GuestUsize;
let avail_ring_size = 6 + 2 * u64::from(queue_size) as GuestUsize;
let used_ring_size = 6 + 8 * u64::from(queue_size) as GuestUsize;
if GuestAddress(config_data.desc_table_addr)
.checked_add(desc_table_size)
.map_or(true, |v| !self.mem().address_in_range(v))
{
@ -72,9 +77,10 @@ pub trait VhostKernBackend<'a>: AsRawFd {
.map_or(true, |v| !self.mem().address_in_range(v))
{
false
} else {
true
}
*/
config_data.is_log_addr_valid()
}
}
@ -186,33 +192,13 @@ impl<'a, T: VhostKernBackend<'a>> VhostBackend for T {
return Err(Error::InvalidQueue);
}
let desc_addr = self
.mem()
.get_host_address(GuestAddress(config_data.desc_table_addr))
.map_err(|_| Error::InvalidGuestMemory)?;
let used_addr = self
.mem()
.get_host_address(GuestAddress(config_data.used_ring_addr))
.map_err(|_| Error::InvalidGuestMemory)?;
let avail_addr = self
.mem()
.get_host_address(GuestAddress(config_data.avail_ring_addr))
.map_err(|_| Error::InvalidGuestMemory)?;
let log_addr = match config_data.log_addr {
None => null(),
Some(a) => self
.mem()
.get_host_address(GuestAddress(a))
.map_err(|_| Error::InvalidGuestMemory)?,
};
let vring_addr = vhost_vring_addr {
index: queue_index as u32,
flags: config_data.flags,
desc_user_addr: desc_addr as u64,
used_user_addr: used_addr as u64,
avail_user_addr: avail_addr as u64,
log_guest_addr: log_addr as u64,
desc_user_addr: config_data.desc_table_addr,
used_user_addr: config_data.used_ring_addr,
avail_user_addr: config_data.avail_ring_addr,
log_guest_addr: config_data.get_log_addr(),
};
// This ioctl is called on a valid vhost fd and has its