virtio-devices: modify or provide safety comments

Signed-off-by: Wei Liu <liuwe@microsoft.com>
This commit is contained in:
Wei Liu 2022-11-16 22:42:25 +00:00 committed by Liu Wei
parent f110029acf
commit c45d24df16
12 changed files with 41 additions and 9 deletions

View File

@ -128,8 +128,8 @@ impl BalloonEpollHandler {
let hva = memory let hva = memory
.get_host_address(range_base) .get_host_address(range_base)
.map_err(Error::GuestMemory)?; .map_err(Error::GuestMemory)?;
// Need unsafe to do syscall madvise
let res = let res =
// SAFETY: Need unsafe to do syscall madvise
unsafe { libc::madvise(hva as *mut libc::c_void, range_len as libc::size_t, advice) }; unsafe { libc::madvise(hva as *mut libc::c_void, range_len as libc::size_t, advice) };
if res != 0 { if res != 0 {
return Err(Error::MadviseFail(io::Error::last_os_error())); return Err(Error::MadviseFail(io::Error::last_os_error()));
@ -147,6 +147,7 @@ impl BalloonEpollHandler {
))?; ))?;
if let Some(f_off) = region.file_offset() { if let Some(f_off) = region.file_offset() {
let offset = range_base.0 - region.start_addr().0; let offset = range_base.0 - region.start_addr().0;
// SAFETY: FFI call with valid arguments
let res = unsafe { let res = unsafe {
libc::fallocate64( libc::fallocate64(
f_off.file().as_raw_fd(), f_off.file().as_raw_fd(),

View File

@ -607,6 +607,7 @@ fn get_win_size(tty: &dyn AsRawFd) -> (u16, u16) {
} }
let ws: WindowSize = WindowSize::default(); let ws: WindowSize = WindowSize::default();
// SAFETY: FFI call with correct arguments
unsafe { unsafe {
libc::ioctl(tty.as_raw_fd(), TIOCGWINSZ, &ws); libc::ioctl(tty.as_raw_fd(), TIOCGWINSZ, &ws);
} }

View File

@ -87,6 +87,7 @@ impl EpollHelper {
// Create the epoll file descriptor // Create the epoll file descriptor
let epoll_fd = epoll::create(true).map_err(EpollHelperError::CreateFd)?; let epoll_fd = epoll::create(true).map_err(EpollHelperError::CreateFd)?;
// Use 'File' to enforce closing on 'epoll_fd' // Use 'File' to enforce closing on 'epoll_fd'
// SAFETY: epoll_fd is a valid fd
let epoll_file = unsafe { File::from_raw_fd(epoll_fd) }; let epoll_file = unsafe { File::from_raw_fd(epoll_fd) };
let mut helper = Self { let mut helper = Self {

View File

@ -267,19 +267,31 @@ struct VirtioIommuFault {
address: u64, address: u64,
} }
// SAFETY: these data structures only contain integers and have no implicit padding // SAFETY: data structure only contain integers and have no implicit padding
unsafe impl ByteValued for VirtioIommuRange32 {} unsafe impl ByteValued for VirtioIommuRange32 {}
// SAFETY: data structure only contain integers and have no implicit padding
unsafe impl ByteValued for VirtioIommuRange64 {} unsafe impl ByteValued for VirtioIommuRange64 {}
// SAFETY: data structure only contain integers and have no implicit padding
unsafe impl ByteValued for VirtioIommuConfig {} unsafe impl ByteValued for VirtioIommuConfig {}
// SAFETY: data structure only contain integers and have no implicit padding
unsafe impl ByteValued for VirtioIommuReqHead {} unsafe impl ByteValued for VirtioIommuReqHead {}
// SAFETY: data structure only contain integers and have no implicit padding
unsafe impl ByteValued for VirtioIommuReqTail {} unsafe impl ByteValued for VirtioIommuReqTail {}
// SAFETY: data structure only contain integers and have no implicit padding
unsafe impl ByteValued for VirtioIommuReqAttach {} unsafe impl ByteValued for VirtioIommuReqAttach {}
// SAFETY: data structure only contain integers and have no implicit padding
unsafe impl ByteValued for VirtioIommuReqDetach {} unsafe impl ByteValued for VirtioIommuReqDetach {}
// SAFETY: data structure only contain integers and have no implicit padding
unsafe impl ByteValued for VirtioIommuReqMap {} unsafe impl ByteValued for VirtioIommuReqMap {}
// SAFETY: data structure only contain integers and have no implicit padding
unsafe impl ByteValued for VirtioIommuReqUnmap {} unsafe impl ByteValued for VirtioIommuReqUnmap {}
// SAFETY: data structure only contain integers and have no implicit padding
unsafe impl ByteValued for VirtioIommuReqProbe {} unsafe impl ByteValued for VirtioIommuReqProbe {}
// SAFETY: data structure only contain integers and have no implicit padding
unsafe impl ByteValued for VirtioIommuProbeProperty {} unsafe impl ByteValued for VirtioIommuProbeProperty {}
// SAFETY: data structure only contain integers and have no implicit padding
unsafe impl ByteValued for VirtioIommuProbeResvMem {} unsafe impl ByteValued for VirtioIommuProbeResvMem {}
// SAFETY: data structure only contain integers and have no implicit padding
unsafe impl ByteValued for VirtioIommuFault {} unsafe impl ByteValued for VirtioIommuFault {}
#[derive(Error, Debug)] #[derive(Error, Debug)]

View File

@ -417,6 +417,7 @@ impl MemEpollHandler {
fn discard_memory_range(&self, offset: u64, size: u64) -> Result<(), Error> { fn discard_memory_range(&self, offset: u64, size: u64) -> Result<(), Error> {
// Use fallocate if the memory region is backed by a file. // Use fallocate if the memory region is backed by a file.
if let Some(fd) = self.host_fd { if let Some(fd) = self.host_fd {
// SAFETY: FFI call with valid arguments
let res = unsafe { let res = unsafe {
libc::fallocate64( libc::fallocate64(
fd, fd,
@ -435,6 +436,7 @@ impl MemEpollHandler {
// Only use madvise if the memory region is not allocated with // Only use madvise if the memory region is not allocated with
// hugepages. // hugepages.
if !self.hugepages { if !self.hugepages {
// SAFETY: FFI call with valid arguments
let res = unsafe { let res = unsafe {
libc::madvise( libc::madvise(
(self.host_addr + offset) as *mut libc::c_void, (self.host_addr + offset) as *mut libc::c_void,

View File

@ -666,8 +666,8 @@ impl VirtioPciDevice {
.unwrap(); .unwrap();
} }
} else { } else {
// Safe since we know self.cap_pci_cfg_info.cap.cap.offset is 32bits long.
let bar_offset: u32 = let bar_offset: u32 =
// SAFETY: we know self.cap_pci_cfg_info.cap.cap.offset is 32bits long.
unsafe { std::mem::transmute(self.cap_pci_cfg_info.cap.cap.offset) }; unsafe { std::mem::transmute(self.cap_pci_cfg_info.cap.cap.offset) };
self.read_bar(0, bar_offset as u64, data) self.read_bar(0, bar_offset as u64, data)
} }
@ -687,8 +687,8 @@ impl VirtioPciDevice {
right[..data_len].copy_from_slice(data); right[..data_len].copy_from_slice(data);
None None
} else { } else {
// Safe since we know self.cap_pci_cfg_info.cap.cap.offset is 32bits long.
let bar_offset: u32 = let bar_offset: u32 =
// SAFETY: we know self.cap_pci_cfg_info.cap.cap.offset is 32bits long.
unsafe { std::mem::transmute(self.cap_pci_cfg_info.cap.cap.offset) }; unsafe { std::mem::transmute(self.cap_pci_cfg_info.cap.cap.offset) };
self.write_bar(0, bar_offset as u64, data) self.write_bar(0, bar_offset as u64, data)
} }

View File

@ -95,6 +95,7 @@ impl VhostUserMasterReqHandler for SlaveReqHandler {
let addr = self.mmap_cache_addr + offset; let addr = self.mmap_cache_addr + offset;
let flags = fs.flags[i]; let flags = fs.flags[i];
// SAFETY: FFI call with valid arguments
let ret = unsafe { let ret = unsafe {
libc::mmap( libc::mmap(
addr as *mut libc::c_void, addr as *mut libc::c_void,
@ -136,6 +137,7 @@ impl VhostUserMasterReqHandler for SlaveReqHandler {
} }
let addr = self.mmap_cache_addr + offset; let addr = self.mmap_cache_addr + offset;
// SAFETY: FFI call with valid arguments
let ret = unsafe { let ret = unsafe {
libc::mmap( libc::mmap(
addr as *mut libc::c_void, addr as *mut libc::c_void,
@ -172,6 +174,7 @@ impl VhostUserMasterReqHandler for SlaveReqHandler {
let addr = self.mmap_cache_addr + offset; let addr = self.mmap_cache_addr + offset;
let ret = let ret =
// SAFETY: FFI call with valid arguments
unsafe { libc::msync(addr as *mut libc::c_void, len as usize, libc::MS_SYNC) }; unsafe { libc::msync(addr as *mut libc::c_void, len as usize, libc::MS_SYNC) };
if ret == -1 { if ret == -1 {
return Err(io::Error::last_os_error()); return Err(io::Error::last_os_error());
@ -228,6 +231,7 @@ impl VhostUserMasterReqHandler for SlaveReqHandler {
== VhostUserFSSlaveMsgFlags::MAP_W == VhostUserFSSlaveMsgFlags::MAP_W
{ {
debug!("write: foffset={}, len={}", foffset, len); debug!("write: foffset={}, len={}", foffset, len);
// SAFETY: FFI call with valid arguments
unsafe { unsafe {
pwrite64( pwrite64(
fd.as_raw_fd(), fd.as_raw_fd(),
@ -238,6 +242,7 @@ impl VhostUserMasterReqHandler for SlaveReqHandler {
} }
} else { } else {
debug!("read: foffset={}, len={}", foffset, len); debug!("read: foffset={}, len={}", foffset, len);
// SAFETY: FFI call with valid arguments
unsafe { pread64(fd.as_raw_fd(), ptr as *mut c_void, len, foffset as off64_t) } unsafe { pread64(fd.as_raw_fd(), ptr as *mut c_void, len, foffset as off64_t) }
}; };
@ -279,6 +284,7 @@ impl Default for VirtioFsConfig {
} }
} }
// SAFETY: only a series of integers
unsafe impl ByteValued for VirtioFsConfig {} unsafe impl ByteValued for VirtioFsConfig {}
pub struct Fs { pub struct Fs {

View File

@ -375,6 +375,7 @@ impl VhostUserCommon {
pub fn shutdown(&mut self) { pub fn shutdown(&mut self) {
if let Some(vu) = &self.vu { if let Some(vu) = &self.vu {
// SAFETY: trivially safe
let _ = unsafe { libc::close(vu.lock().unwrap().socket_handle().as_raw_fd()) }; let _ = unsafe { libc::close(vu.lock().unwrap().socket_handle().as_raw_fd()) };
} }

View File

@ -451,7 +451,7 @@ impl VhostUserHandle {
) )
.map_err(Error::MemfdCreate)?; .map_err(Error::MemfdCreate)?;
// Safe because we checked the file descriptor is valid // SAFETY: we checked the file descriptor is valid
let file = unsafe { File::from_raw_fd(fd) }; let file = unsafe { File::from_raw_fd(fd) };
// The size of the memory mapping corresponds to the size of a bitmap // The size of the memory mapping corresponds to the size of a bitmap
// covering all guest pages for addresses from 0 to the last physical // covering all guest pages for addresses from 0 to the last physical
@ -465,6 +465,7 @@ impl VhostUserHandle {
file.set_len(mmap_size).map_err(Error::SetFileSize)?; file.set_len(mmap_size).map_err(Error::SetFileSize)?;
// Set the seals // Set the seals
// SAFETY: FFI call with valid arguments
let res = unsafe { let res = unsafe {
libc::fcntl( libc::fcntl(
file.as_raw_fd(), file.as_raw_fd(),
@ -569,6 +570,7 @@ impl VhostUserHandle {
// Be careful with the size, as it was based on u8, meaning we must // Be careful with the size, as it was based on u8, meaning we must
// divide it by 8. // divide it by 8.
let len = region.size() / 8; let len = region.size() / 8;
// SAFETY: region is of size len
let bitmap = unsafe { let bitmap = unsafe {
// Cast the pointer to u64 // Cast the pointer to u64
let ptr = region.as_ptr() as *const u64; let ptr = region.as_ptr() as *const u64;
@ -582,6 +584,7 @@ impl VhostUserHandle {
} }
fn memfd_create(name: &ffi::CStr, flags: u32) -> std::result::Result<RawFd, std::io::Error> { fn memfd_create(name: &ffi::CStr, flags: u32) -> std::result::Result<RawFd, std::io::Error> {
// SAFETY: FFI call with valid arguments
let res = unsafe { libc::syscall(libc::SYS_memfd_create, name.as_ptr(), flags) }; let res = unsafe { libc::syscall(libc::SYS_memfd_create, name.as_ptr(), flags) };
if res < 0 { if res < 0 {

View File

@ -239,7 +239,7 @@ impl VsockPacket {
/// Provides in-place, byte-slice, access to the vsock packet header. /// Provides in-place, byte-slice, access to the vsock packet header.
/// ///
pub fn hdr(&self) -> &[u8] { pub fn hdr(&self) -> &[u8] {
// This is safe since bound checks have already been performed when creating the packet // SAFETY: bound checks have already been performed when creating the packet
// from the virtq descriptor. // from the virtq descriptor.
unsafe { std::slice::from_raw_parts(self.hdr as *const u8, VSOCK_PKT_HDR_SIZE) } unsafe { std::slice::from_raw_parts(self.hdr as *const u8, VSOCK_PKT_HDR_SIZE) }
} }
@ -247,7 +247,7 @@ impl VsockPacket {
/// Provides in-place, byte-slice, mutable access to the vsock packet header. /// Provides in-place, byte-slice, mutable access to the vsock packet header.
/// ///
pub fn hdr_mut(&mut self) -> &mut [u8] { pub fn hdr_mut(&mut self) -> &mut [u8] {
// This is safe since bound checks have already been performed when creating the packet // SAFETY: bound checks have already been performed when creating the packet
// from the virtq descriptor. // from the virtq descriptor.
unsafe { std::slice::from_raw_parts_mut(self.hdr, VSOCK_PKT_HDR_SIZE) } unsafe { std::slice::from_raw_parts_mut(self.hdr, VSOCK_PKT_HDR_SIZE) }
} }
@ -261,7 +261,7 @@ impl VsockPacket {
/// is stored in the packet header, and accessible via `VsockPacket::len()`. /// is stored in the packet header, and accessible via `VsockPacket::len()`.
pub fn buf(&self) -> Option<&[u8]> { pub fn buf(&self) -> Option<&[u8]> {
self.buf.map(|ptr| { self.buf.map(|ptr| {
// This is safe since bound checks have already been performed when creating the packet // SAFETY: bound checks have already been performed when creating the packet
// from the virtq descriptor. // from the virtq descriptor.
unsafe { std::slice::from_raw_parts(ptr as *const u8, self.buf_size) } unsafe { std::slice::from_raw_parts(ptr as *const u8, self.buf_size) }
}) })
@ -276,7 +276,7 @@ impl VsockPacket {
/// is stored in the packet header, and accessible via `VsockPacket::len()`. /// is stored in the packet header, and accessible via `VsockPacket::len()`.
pub fn buf_mut(&mut self) -> Option<&mut [u8]> { pub fn buf_mut(&mut self) -> Option<&mut [u8]> {
self.buf.map(|ptr| { self.buf.map(|ptr| {
// This is safe since bound checks have already been performed when creating the packet // SAFETY: bound checks have already been performed when creating the packet
// from the virtq descriptor. // from the virtq descriptor.
unsafe { std::slice::from_raw_parts_mut(ptr, self.buf_size) } unsafe { std::slice::from_raw_parts_mut(ptr, self.buf_size) }
}) })
@ -383,6 +383,7 @@ impl VsockPacket {
} }
#[cfg(test)] #[cfg(test)]
#[allow(clippy::undocumented_unsafe_blocks)]
mod tests { mod tests {
use super::super::tests::TestContext; use super::super::tests::TestContext;
use super::*; use super::*;

View File

@ -334,6 +334,7 @@ impl VsockMuxer {
// device activation time. // device activation time.
let epoll_fd = epoll::create(true).map_err(Error::EpollFdCreate)?; let epoll_fd = epoll::create(true).map_err(Error::EpollFdCreate)?;
// Use 'File' to enforce closing on 'epoll_fd' // Use 'File' to enforce closing on 'epoll_fd'
// SAFETY: epoll_fd is a valid fd
let epoll_file = unsafe { File::from_raw_fd(epoll_fd) }; let epoll_file = unsafe { File::from_raw_fd(epoll_fd) };
// Open/bind/listen on the host Unix socket, so we can accept host-initiated // Open/bind/listen on the host Unix socket, so we can accept host-initiated

View File

@ -235,6 +235,7 @@ impl Watchdog {
error!("Failed to create timer fd {}", e); error!("Failed to create timer fd {}", e);
e e
})?; })?;
// SAFETY: timer_fd is a valid fd
let timer = unsafe { File::from_raw_fd(timer_fd) }; let timer = unsafe { File::from_raw_fd(timer_fd) };
Ok(Watchdog { Ok(Watchdog {
@ -280,6 +281,7 @@ impl Drop for Watchdog {
} }
fn timerfd_create() -> Result<RawFd, io::Error> { fn timerfd_create() -> Result<RawFd, io::Error> {
// SAFETY: FFI call, trivially safe
let res = unsafe { libc::timerfd_create(libc::CLOCK_MONOTONIC, 0) }; let res = unsafe { libc::timerfd_create(libc::CLOCK_MONOTONIC, 0) };
if res < 0 { if res < 0 {
Err(io::Error::last_os_error()) Err(io::Error::last_os_error())
@ -301,6 +303,7 @@ fn timerfd_setup(timer: &File, secs: i64) -> Result<(), io::Error> {
}; };
let res = let res =
// SAFETY: FFI call with correct arguments
unsafe { libc::timerfd_settime(timer.as_raw_fd(), 0, &periodic, std::ptr::null_mut()) }; unsafe { libc::timerfd_settime(timer.as_raw_fd(), 0, &periodic, std::ptr::null_mut()) };
if res < 0 { if res < 0 {