@@ -21,7 +21,7 @@ mod x86_64_target;
2121use std:: io:: { self , ErrorKind } ;
2222use std:: net:: TcpListener ;
2323use std:: sync:: { Arc , Mutex } ;
24- use std:: { slice , thread} ;
24+ use std:: thread;
2525
2626use crossbeam_channel:: { Receiver , Sender , TryRecvError } ;
2727use event_loop:: event_loop_thread;
@@ -36,10 +36,10 @@ use super::regs::CommonRegisters;
3636use crate :: HyperlightError ;
3737use crate :: hypervisor:: regs:: CommonFpu ;
3838use crate :: hypervisor:: virtual_machine:: { HypervisorError , RegisterError , VirtualMachine } ;
39- use crate :: mem:: layout:: SandboxMemoryLayout ;
39+ use crate :: mem:: layout:: BaseGpaRegion ;
4040use crate :: mem:: memory_region:: MemoryRegion ;
4141use crate :: mem:: mgr:: SandboxMemoryManager ;
42- use crate :: mem:: shared_mem:: { HostSharedMemory , SharedMemory } ;
42+ use crate :: mem:: shared_mem:: HostSharedMemory ;
4343
4444#[ derive( Debug , Error ) ]
4545pub enum GdbTargetError {
@@ -95,18 +95,11 @@ pub enum DebugMemoryAccessError {
9595 LockFailed ( & ' static str , u32 , String ) ,
9696 #[ error( "Failed to translate guest address {0:#x}" ) ]
9797 TranslateGuestAddress ( u64 ) ,
98+ #[ error( "Failed to write to read-only region" ) ]
99+ WriteToReadOnly ,
98100}
99101
100102impl DebugMemoryAccess {
101- // TODO: There is a lot of common logic between both of these
102- // functions, as well as guest_page/access_gpa in snapshot.rs. It
103- // would be nice to factor that out at some point, but the
104- // snapshot versions deal with ExclusiveSharedMemory, since we
105- // never expect a guest to be running concurrent with a snapshot,
106- // and doesn't want to make unnecessary copies, since it runs over
107- // relatively large volumes of data, so it's not clear if it's
108- // terribly easy to combine them
109-
110103 /// Reads memory from the guest's address space with a maximum length of a PAGE_SIZE
111104 ///
112105 /// # Arguments
@@ -120,74 +113,17 @@ impl DebugMemoryAccess {
120113 data : & mut [ u8 ] ,
121114 gpa : u64 ,
122115 ) -> std:: result:: Result < ( ) , DebugMemoryAccessError > {
123- let read_len = data. len ( ) ;
124-
125- let mem_offset = ( gpa as usize )
126- . checked_sub ( SandboxMemoryLayout :: BASE_ADDRESS )
127- . ok_or_else ( || {
128- log:: warn!(
129- "gpa={:#X} causes subtract with underflow: \" gpa - BASE_ADDRESS={:#X}-{:#X}\" " ,
130- gpa,
131- gpa,
132- SandboxMemoryLayout :: BASE_ADDRESS
133- ) ;
134- DebugMemoryAccessError :: TranslateGuestAddress ( gpa)
135- } ) ?;
136-
137- // First check the mapped memory regions to see if the address is within any of them
138- let mut region_found = false ;
139- for reg in self . guest_mmap_regions . iter ( ) {
140- if reg. guest_region . contains ( & mem_offset) {
141- log:: debug!( "Found mapped region containing {:X}: {:#?}" , gpa, reg) ;
142-
143- // Region found - calculate the offset within the region
144- let region_offset = mem_offset. checked_sub ( reg. guest_region . start ) . ok_or_else ( || {
145- log:: warn!(
146- "Cannot calculate offset in memory region: mem_offset={:#X}, base={:#X}" ,
147- mem_offset,
148- reg. guest_region. start,
149- ) ;
150- DebugMemoryAccessError :: TranslateGuestAddress ( mem_offset as u64 )
151- } ) ?;
152-
153- let host_start_ptr = <_ as Into < usize > >:: into ( reg. host_region . start ) ;
154- let bytes: & [ u8 ] = unsafe {
155- slice:: from_raw_parts ( host_start_ptr as * const u8 , reg. guest_region . len ( ) )
156- } ;
157- data[ ..read_len] . copy_from_slice ( & bytes[ region_offset..region_offset + read_len] ) ;
158-
159- region_found = true ;
160- break ;
161- }
162- }
163-
164- if !region_found {
165- let mut mgr = self
166- . dbg_mem_access_fn
167- . try_lock ( )
168- . map_err ( |e| DebugMemoryAccessError :: LockFailed ( file ! ( ) , line ! ( ) , e. to_string ( ) ) ) ?;
169- let scratch_base =
170- hyperlight_common:: layout:: scratch_base_gpa ( mgr. scratch_mem . mem_size ( ) ) ;
171- let ( mem, offset, name) : ( & mut HostSharedMemory , _ , _ ) = if gpa >= scratch_base {
172- (
173- & mut mgr. scratch_mem ,
174- ( gpa - scratch_base) as usize ,
175- "scratch" ,
176- )
177- } else {
178- ( & mut mgr. shared_mem , mem_offset, "snapshot" )
179- } ;
180- log:: debug!(
181- "No mapped region found containing {:X}. Trying {} memory at offset {:X} ..." ,
182- gpa,
183- name,
184- offset
185- ) ;
186- mem. copy_to_slice ( & mut data[ ..read_len] , offset)
187- . map_err ( |e| DebugMemoryAccessError :: CopyFailed ( Box :: new ( e) ) ) ?;
188- }
189-
190- Ok ( ( ) )
116+ let mgr = self
117+ . dbg_mem_access_fn
118+ . try_lock ( )
119+ . map_err ( |e| DebugMemoryAccessError :: LockFailed ( file ! ( ) , line ! ( ) , e. to_string ( ) ) ) ?;
120+
121+ mgr. layout
122+ . resolve_gpa ( gpa, & self . guest_mmap_regions )
123+ . ok_or ( DebugMemoryAccessError :: TranslateGuestAddress ( gpa) ) ?
124+ . with_memories ( & mgr. shared_mem , & mgr. scratch_mem )
125+ . copy_to_slice ( data)
126+ . map_err ( |e| DebugMemoryAccessError :: CopyFailed ( Box :: new ( e) ) )
191127 }
192128
193129 /// Writes memory from the guest's address space with a maximum length of a PAGE_SIZE
@@ -203,74 +139,30 @@ impl DebugMemoryAccess {
203139 data : & [ u8 ] ,
204140 gpa : u64 ,
205141 ) -> std:: result:: Result < ( ) , DebugMemoryAccessError > {
206- let write_len = data. len ( ) ;
207-
208- let mem_offset = ( gpa as usize )
209- . checked_sub ( SandboxMemoryLayout :: BASE_ADDRESS )
210- . ok_or_else ( || {
211- log:: warn!(
212- "gpa={:#X} causes subtract with underflow: \" gpa - BASE_ADDRESS={:#X}-{:#X}\" " ,
213- gpa,
214- gpa,
215- SandboxMemoryLayout :: BASE_ADDRESS
216- ) ;
217- DebugMemoryAccessError :: TranslateGuestAddress ( gpa)
218- } ) ?;
219-
220- // First check the mapped memory regions to see if the address is within any of them
221- let mut region_found = false ;
222- for reg in self . guest_mmap_regions . iter ( ) {
223- if reg. guest_region . contains ( & mem_offset) {
224- log:: debug!( "Found mapped region containing {:X}: {:#?}" , gpa, reg) ;
225-
226- // Region found - calculate the offset within the region
227- let region_offset = mem_offset. checked_sub ( reg. guest_region . start ) . ok_or_else ( || {
228- log:: warn!(
229- "Cannot calculate offset in memory region: mem_offset={:#X}, base={:#X}" ,
230- mem_offset,
231- reg. guest_region. start,
232- ) ;
233- DebugMemoryAccessError :: TranslateGuestAddress ( mem_offset as u64 )
234- } ) ?;
235-
236- let host_start_ptr = <_ as Into < usize > >:: into ( reg. host_region . start ) ;
237- let bytes: & mut [ u8 ] = unsafe {
238- slice:: from_raw_parts_mut ( host_start_ptr as * mut u8 , reg. guest_region . len ( ) )
239- } ;
240- bytes[ region_offset..region_offset + write_len] . copy_from_slice ( & data[ ..write_len] ) ;
241-
242- region_found = true ;
243- break ;
244- }
245- }
246-
247- if !region_found {
248- let mut mgr = self
249- . dbg_mem_access_fn
250- . try_lock ( )
251- . map_err ( |e| DebugMemoryAccessError :: LockFailed ( file ! ( ) , line ! ( ) , e. to_string ( ) ) ) ?;
252- let scratch_base =
253- hyperlight_common:: layout:: scratch_base_gpa ( mgr. scratch_mem . mem_size ( ) ) ;
254- let ( mem, offset, name) : ( & mut HostSharedMemory , _ , _ ) = if gpa >= scratch_base {
255- (
256- & mut mgr. scratch_mem ,
257- ( gpa - scratch_base) as usize ,
258- "scratch" ,
259- )
260- } else {
261- ( & mut mgr. shared_mem , mem_offset, "snapshot" )
262- } ;
263- log:: debug!(
264- "No mapped region found containing {:X}. Trying {} memory at offset {:X} ..." ,
265- gpa,
266- name,
267- offset
268- ) ;
269- mem. copy_from_slice ( & data[ ..write_len] , offset)
270- . map_err ( |e| DebugMemoryAccessError :: CopyFailed ( Box :: new ( e) ) ) ?;
142+ let mgr = self
143+ . dbg_mem_access_fn
144+ . try_lock ( )
145+ . map_err ( |e| DebugMemoryAccessError :: LockFailed ( file ! ( ) , line ! ( ) , e. to_string ( ) ) ) ?;
146+
147+ let resolved = mgr
148+ . layout
149+ . resolve_gpa ( gpa, & self . guest_mmap_regions )
150+ . ok_or ( DebugMemoryAccessError :: TranslateGuestAddress ( gpa) ) ?;
151+
152+ // We can only safely write (without causing UB in the host
153+ // process) if the address is in the scratch region
154+ match resolved. base {
155+ #[ cfg( unshared_snapshot_mem) ]
156+ BaseGpaRegion :: Snapshot ( ( ) ) => mgr
157+ . shared_mem
158+ . copy_from_slice ( data, resolved. offset )
159+ . map_err ( |e| DebugMemoryAccessError :: CopyFailed ( Box :: new ( e) ) ) ,
160+ BaseGpaRegion :: Scratch ( ( ) ) => mgr
161+ . scratch_mem
162+ . copy_from_slice ( data, resolved. offset )
163+ . map_err ( |e| DebugMemoryAccessError :: CopyFailed ( Box :: new ( e) ) ) ,
164+ _ => Err ( DebugMemoryAccessError :: WriteToReadOnly ) ,
271165 }
272-
273- Ok ( ( ) )
274166 }
275167}
276168
@@ -490,6 +382,7 @@ mod tests {
490382 use hyperlight_testing:: dummy_guest_as_string;
491383
492384 use super :: * ;
385+ use crate :: mem:: layout:: SandboxMemoryLayout ;
493386 use crate :: mem:: memory_region:: { MemoryRegionFlags , MemoryRegionType } ;
494387 use crate :: sandbox:: UninitializedSandbox ;
495388 use crate :: sandbox:: uninitialized:: GuestBinary ;
0 commit comments