Skip to content

Commit 1e63116

Browse files
committed
add helper for Read/Write[Volatile] through bounce buffer
With secret freedom, direct accesses to guest memory from the context of the host kernel are no longer possible. This particularly means that we cannot pass pointers to guest memory to the host kernel anymore (at least if the host kernel tries to GUP them). For these scenarios, introduce a utility decorator struct `MaybeBounce` that can optionally do indirect read and write syscalls on guest memory by first memcpy-ing to firecracker userspace, and passing a pointer to firecracker heap memory into the kernel instead. Signed-off-by: Patrick Roy <roypat@amazon.co.uk>
1 parent 087a589 commit 1e63116

File tree

1 file changed

+89
-2
lines changed

1 file changed

+89
-2
lines changed

src/vmm/src/vstate/memory.rs

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// found in the THIRD-PARTY file.
77

88
use std::fs::File;
9-
use std::io::SeekFrom;
9+
use std::io::{Read, Seek, SeekFrom};
1010
use std::sync::Arc;
1111

1212
use serde::{Deserialize, Serialize};
@@ -17,7 +17,10 @@ pub use vm_memory::{
1717
Address, ByteValued, Bytes, FileOffset, GuestAddress, GuestMemory, GuestMemoryRegion,
1818
GuestUsize, MemoryRegionAddress, MmapRegion, address,
1919
};
20-
use vm_memory::{Error as VmMemoryError, GuestMemoryError, WriteVolatile};
20+
use vm_memory::{
21+
Error as VmMemoryError, GuestMemoryError, ReadVolatile, VolatileMemoryError, VolatileSlice,
22+
WriteVolatile,
23+
};
2124
use vmm_sys_util::errno;
2225

2326
use crate::DirtyBitmap;
@@ -50,6 +53,58 @@ pub enum MemoryError {
5053
OffsetTooLarge,
5154
}
5255

56+
/// Newtype that implements [`ReadVolatile`] and [`WriteVolatile`] if `T` implements `Read` or
57+
/// `Write` respectively, by reading/writing using a bounce buffer, and memcpy-ing into the
58+
/// [`VolatileSlice`].
59+
#[derive(Debug)]
60+
pub struct MaybeBounce<T>(pub T, pub bool);
61+
62+
impl<T: ReadVolatile> ReadVolatile for MaybeBounce<T> {
63+
fn read_volatile<B: BitmapSlice>(
64+
&mut self,
65+
buf: &mut VolatileSlice<B>,
66+
) -> Result<usize, VolatileMemoryError> {
67+
if self.1 {
68+
let mut bbuf = vec![0; buf.len()];
69+
let n = self
70+
.0
71+
.read_volatile(&mut VolatileSlice::from(bbuf.as_mut_slice()))?;
72+
buf.copy_from(&bbuf[..n]);
73+
Ok(n)
74+
} else {
75+
self.0.read_volatile(buf)
76+
}
77+
}
78+
}
79+
80+
impl<T: WriteVolatile> WriteVolatile for MaybeBounce<T> {
81+
fn write_volatile<B: BitmapSlice>(
82+
&mut self,
83+
buf: &VolatileSlice<B>,
84+
) -> Result<usize, VolatileMemoryError> {
85+
if self.1 {
86+
let mut bbuf = vec![0; buf.len()];
87+
buf.copy_to(bbuf.as_mut_slice());
88+
self.0
89+
.write_volatile(&VolatileSlice::from(bbuf.as_mut_slice()))
90+
} else {
91+
self.0.write_volatile(buf)
92+
}
93+
}
94+
}
95+
96+
impl<R: Read> Read for MaybeBounce<R> {
97+
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
98+
self.0.read(buf)
99+
}
100+
}
101+
102+
impl<S: Seek> Seek for MaybeBounce<S> {
103+
fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
104+
self.0.seek(pos)
105+
}
106+
}
107+
53108
/// Creates a `Vec` of `GuestRegionMmap` with the given configuration
54109
pub fn create(
55110
regions: impl Iterator<Item = (GuestAddress, usize)>,
@@ -346,6 +401,7 @@ mod tests {
346401

347402
use std::collections::HashMap;
348403
use std::io::{Read, Seek};
404+
use std::os::fd::AsFd;
349405

350406
use vmm_sys_util::tempfile::TempFile;
351407

@@ -722,4 +778,35 @@ mod tests {
722778
seals.insert(memfd::FileSeal::SealGrow);
723779
memfd.add_seals(&seals).unwrap_err();
724780
}
781+
782+
#[test]
783+
fn test_bounce() {
784+
let file_direct = TempFile::new().unwrap();
785+
let file_bounced = TempFile::new().unwrap();
786+
787+
let mut data = (0..=255).collect::<Vec<_>>();
788+
789+
MaybeBounce(file_direct.as_file().as_fd(), false)
790+
.write_all_volatile(&VolatileSlice::from(data.as_mut_slice()))
791+
.unwrap();
792+
MaybeBounce(file_bounced.as_file().as_fd(), true)
793+
.write_all_volatile(&VolatileSlice::from(data.as_mut_slice()))
794+
.unwrap();
795+
796+
let mut data_direct = vec![0u8; 256];
797+
let mut data_bounced = vec![0u8; 256];
798+
799+
file_direct.as_file().seek(SeekFrom::Start(0)).unwrap();
800+
file_bounced.as_file().seek(SeekFrom::Start(0)).unwrap();
801+
802+
MaybeBounce(file_direct.as_file().as_fd(), false)
803+
.read_exact_volatile(&mut VolatileSlice::from(data_direct.as_mut_slice()))
804+
.unwrap();
805+
MaybeBounce(file_bounced.as_file().as_fd(), true)
806+
.read_exact_volatile(&mut VolatileSlice::from(data_bounced.as_mut_slice()))
807+
.unwrap();
808+
809+
assert_eq!(data_direct, data_bounced);
810+
assert_eq!(data_direct, data);
811+
}
725812
}

0 commit comments

Comments
 (0)