@@ -9,6 +9,7 @@ use std::num::Wrapping;
9
9
use std:: sync:: atomic:: { Ordering , fence} ;
10
10
11
11
use crate :: logger:: error;
12
+ use crate :: utils:: u64_to_usize;
12
13
use crate :: vstate:: memory:: { Address , Bitmap , ByteValued , GuestAddress , GuestMemory } ;
13
14
14
15
pub const VIRTQ_DESC_F_NEXT : u16 = 0x1 ;
@@ -32,7 +33,7 @@ pub enum QueueError {
32
33
/// Failed to write value into the virtio queue used ring: {0}
33
34
MemoryError ( #[ from] vm_memory:: GuestMemoryError ) ,
34
35
/// Pointer is not aligned properly: {0:#x} not {1}-byte aligned.
35
- PointerNotAligned ( usize , u8 ) ,
36
+ PointerNotAligned ( usize , usize ) ,
36
37
}
37
38
38
39
/// Error type indicating the guest configured a virtio queue such that the avail_idx field would
@@ -310,31 +311,32 @@ impl Queue {
310
311
+ std:: mem:: size_of :: < u16 > ( )
311
312
}
312
313
313
- fn get_slice_ptr < M : GuestMemory > (
314
+ fn get_aligned_slice_ptr < T , M : GuestMemory > (
314
315
& self ,
315
316
mem : & M ,
316
317
addr : GuestAddress ,
317
318
len : usize ,
318
- ) -> Result < * mut u8 , QueueError > {
319
+ alignment : usize ,
320
+ ) -> Result < * mut T , QueueError > {
321
+ // Guest memory base address is page aligned, so as long as alignment divides page size,
322
+ // It suffices to check that the GPA is properly aligned (e.g. we don't need to recheck
323
+ // the HVA).
324
+ if addr. 0 & ( alignment as u64 - 1 ) != 0 {
325
+ return Err ( QueueError :: PointerNotAligned (
326
+ u64_to_usize ( addr. 0 ) ,
327
+ alignment,
328
+ ) ) ;
329
+ }
330
+
319
331
let slice = mem. get_slice ( addr, len) . map_err ( QueueError :: MemoryError ) ?;
320
332
slice. bitmap ( ) . mark_dirty ( 0 , len) ;
321
- Ok ( slice. ptr_guard_mut ( ) . as_ptr ( ) )
333
+ Ok ( slice. ptr_guard_mut ( ) . as_ptr ( ) . cast ( ) )
322
334
}
323
335
324
336
/// Set up pointers to the queue objects in the guest memory
325
337
/// and mark memory dirty for those objects
326
338
pub fn initialize < M : GuestMemory > ( & mut self , mem : & M ) -> Result < ( ) , QueueError > {
327
- self . desc_table_ptr = self
328
- . get_slice_ptr ( mem, self . desc_table_address , self . desc_table_size ( ) ) ?
329
- . cast ( ) ;
330
- self . avail_ring_ptr = self
331
- . get_slice_ptr ( mem, self . avail_ring_address , self . avail_ring_size ( ) ) ?
332
- . cast ( ) ;
333
- self . used_ring_ptr = self
334
- . get_slice_ptr ( mem, self . used_ring_address , self . used_ring_size ( ) ) ?
335
- . cast ( ) ;
336
-
337
- // All the above pointers are expected to be aligned properly; otherwise some methods (e.g.
339
+ // All the below pointers are verified to be aligned properly; otherwise some methods (e.g.
338
340
// `read_volatile()`) will panic. Such an unalignment is possible when restored from a
339
341
// broken/fuzzed snapshot.
340
342
//
@@ -347,24 +349,12 @@ impl Queue {
347
349
// > Available Ring 2
348
350
// > Used Ring 4
349
351
// > ================ ==========
350
- if !self . desc_table_ptr . cast :: < u128 > ( ) . is_aligned ( ) {
351
- return Err ( QueueError :: PointerNotAligned (
352
- self . desc_table_ptr as usize ,
353
- 16 ,
354
- ) ) ;
355
- }
356
- if !self . avail_ring_ptr . is_aligned ( ) {
357
- return Err ( QueueError :: PointerNotAligned (
358
- self . avail_ring_ptr as usize ,
359
- 2 ,
360
- ) ) ;
361
- }
362
- if !self . used_ring_ptr . cast :: < u32 > ( ) . is_aligned ( ) {
363
- return Err ( QueueError :: PointerNotAligned (
364
- self . used_ring_ptr as usize ,
365
- 4 ,
366
- ) ) ;
367
- }
352
+ self . desc_table_ptr =
353
+ self . get_aligned_slice_ptr ( mem, self . desc_table_address , self . desc_table_size ( ) , 16 ) ?;
354
+ self . avail_ring_ptr =
355
+ self . get_aligned_slice_ptr ( mem, self . avail_ring_address , self . avail_ring_size ( ) , 2 ) ?;
356
+ self . used_ring_ptr =
357
+ self . get_aligned_slice_ptr ( mem, self . used_ring_address , self . used_ring_size ( ) , 4 ) ?;
368
358
369
359
Ok ( ( ) )
370
360
}
0 commit comments