@@ -34,6 +34,8 @@ pub enum QueueError {
34
34
DescIndexOutOfBounds ( u16 ) ,
35
35
/// Failed to write value into the virtio queue used ring: {0}
36
36
MemoryError ( #[ from] vm_memory:: GuestMemoryError ) ,
37
+ /// Pointer is not aligned properly: {0:#x} not {1}-byte aligned.
38
+ PointerNotAligned ( usize , u8 ) ,
37
39
}
38
40
39
41
/// A virtio descriptor constraints with C representative.
@@ -323,11 +325,36 @@ impl Queue {
323
325
. get_slice_ptr ( mem, self . used_ring_address , self . used_ring_size ( ) ) ?
324
326
. cast ( ) ;
325
327
326
- // Disable it for kani tests, otherwise it will hit this assertion
327
- // and fail.
328
- #[ cfg( not( kani) ) ]
329
- if self . actual_size ( ) < self . len ( ) {
330
- return Err ( QueueError :: InvalidQueueSize ( self . len ( ) , self . actual_size ( ) ) ) ;
328
+ // All the above pointers are expected to be aligned properly; otherwise some methods (e.g.
329
+ // `read_volatile()`) will panic. Such an unalignment is possible when restored from a
330
+ // broken/fuzzed snapshot.
331
+ //
332
+ // Specification of those pointers' alignments
333
+ // https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-350007
334
+ // > ================ ==========
335
+ // > Virtqueue Part Alignment
336
+ // > ================ ==========
337
+ // > Descriptor Table 16
338
+ // > Available Ring 2
339
+ // > Used Ring 4
340
+ // > ================ ==========
341
+ if !self . desc_table_ptr . cast :: < u128 > ( ) . is_aligned ( ) {
342
+ return Err ( QueueError :: PointerNotAligned (
343
+ self . desc_table_ptr as usize ,
344
+ 16 ,
345
+ ) ) ;
346
+ }
347
+ if !self . avail_ring_ptr . is_aligned ( ) {
348
+ return Err ( QueueError :: PointerNotAligned (
349
+ self . avail_ring_ptr as usize ,
350
+ 2 ,
351
+ ) ) ;
352
+ }
353
+ if !self . used_ring_ptr . cast :: < u32 > ( ) . is_aligned ( ) {
354
+ return Err ( QueueError :: PointerNotAligned (
355
+ self . used_ring_ptr as usize ,
356
+ 4 ,
357
+ ) ) ;
331
358
}
332
359
333
360
Ok ( ( ) )
@@ -1234,7 +1261,6 @@ mod verification {
1234
1261
1235
1262
#[ cfg( test) ]
1236
1263
mod tests {
1237
-
1238
1264
use vm_memory:: Bytes ;
1239
1265
1240
1266
pub use super :: * ;
@@ -1644,6 +1670,63 @@ mod tests {
1644
1670
assert_eq ! ( q. used_ring_avail_event_get( ) , 1 ) ;
1645
1671
}
1646
1672
1673
+ #[ test]
1674
+ fn test_initialize_with_aligned_pointer ( ) {
1675
+ let mut q = Queue :: new ( 0 ) ;
1676
+
1677
+ let random_addr = 0x321 ;
1678
+ // Descriptor table must be 16-byte aligned.
1679
+ q. desc_table_address = GuestAddress ( random_addr / 16 * 16 ) ;
1680
+ // Available ring must be 2-byte aligned.
1681
+ q. avail_ring_address = GuestAddress ( random_addr / 2 * 2 ) ;
1682
+ // Used ring must be 4-byte aligned.
1683
+ q. avail_ring_address = GuestAddress ( random_addr / 4 * 4 ) ;
1684
+
1685
+ let mem = single_region_mem ( 0x1000 ) ;
1686
+ q. initialize ( & mem) . unwrap ( ) ;
1687
+ }
1688
+
1689
+ #[ test]
1690
+ fn test_initialize_with_misaligned_pointer ( ) {
1691
+ let mut q = Queue :: new ( 0 ) ;
1692
+ let mem = single_region_mem ( 0x1000 ) ;
1693
+
1694
+ // Descriptor table must be 16-byte aligned.
1695
+ q. desc_table_address = GuestAddress ( 0xb ) ;
1696
+ match q. initialize ( & mem) {
1697
+ Ok ( _) => panic ! ( "Unexpected success" ) ,
1698
+ Err ( QueueError :: PointerNotAligned ( addr, alignment) ) => {
1699
+ assert_eq ! ( addr % 16 , 0xb ) ;
1700
+ assert_eq ! ( alignment, 16 ) ;
1701
+ }
1702
+ Err ( e) => panic ! ( "Unexpected error {e:#?}" ) ,
1703
+ }
1704
+ q. desc_table_address = GuestAddress ( 0x0 ) ;
1705
+
1706
+ // Available ring must be 2-byte aligned.
1707
+ q. avail_ring_address = GuestAddress ( 0x1 ) ;
1708
+ match q. initialize ( & mem) {
1709
+ Ok ( _) => panic ! ( "Unexpected success" ) ,
1710
+ Err ( QueueError :: PointerNotAligned ( addr, alignment) ) => {
1711
+ assert_eq ! ( addr % 2 , 0x1 ) ;
1712
+ assert_eq ! ( alignment, 2 ) ;
1713
+ }
1714
+ Err ( e) => panic ! ( "Unexpected error {e:#?}" ) ,
1715
+ }
1716
+ q. avail_ring_address = GuestAddress ( 0x0 ) ;
1717
+
1718
+ // Used ring must be 4-byte aligned.
1719
+ q. used_ring_address = GuestAddress ( 0x3 ) ;
1720
+ match q. initialize ( & mem) {
1721
+ Ok ( _) => panic ! ( "unexpected success" ) ,
1722
+ Err ( QueueError :: PointerNotAligned ( addr, alignment) ) => {
1723
+ assert_eq ! ( addr % 4 , 0x3 ) ;
1724
+ assert_eq ! ( alignment, 4 ) ;
1725
+ }
1726
+ Err ( e) => panic ! ( "Unexpected error {e:#?}" ) ,
1727
+ }
1728
+ }
1729
+
1647
1730
#[ test]
1648
1731
fn test_queue_error_display ( ) {
1649
1732
let err = QueueError :: MemoryError ( vm_memory:: GuestMemoryError :: InvalidGuestAddress (
0 commit comments