@@ -8,3 +8,127 @@ pub struct BlkInput {
8
8
pub features : u64 ,
9
9
pub device_id : Option < [ u8 ; 20 ] > ,
10
10
}
11
+
12
+ #[ cfg( test) ]
13
+ pub mod tests {
14
+ use super :: * ;
15
+ use crate :: create_corpus_file;
16
+ use crate :: virtio_queue:: DEFAULT_QUEUE_SIZE ;
17
+ use std:: io:: Write ;
18
+ use std:: mem;
19
+ use virtio_bindings:: bindings:: virtio_blk:: VIRTIO_BLK_T_IN ;
20
+ use virtio_bindings:: bindings:: virtio_ring:: { VRING_DESC_F_NEXT , VRING_DESC_F_WRITE } ;
21
+ use virtio_blk:: request:: { Request , RequestType } ;
22
+ use virtio_queue:: { mock:: MockSplitQueue , Descriptor } ;
23
+ use vm_memory:: { ByteValued , Bytes , GuestAddress , GuestMemoryMmap } ;
24
+
25
+ // The same as the RequestHeader type in virtio_blk, with exposed fields
26
+ #[ derive( Clone , Copy , Debug , Default , PartialEq ) ]
27
+ #[ repr( C ) ]
28
+ struct FuzzingBlkRequestHdr {
29
+ request_type : u32 ,
30
+ _reserved : u32 ,
31
+ sector : u64 ,
32
+ }
33
+
34
+ unsafe impl ByteValued for FuzzingBlkRequestHdr { }
35
+
36
+ // Test values for the descriptor chain
37
+ const REQ_TYPE : u32 = VIRTIO_BLK_T_IN ;
38
+ const REQ_SECTOR : u64 = 1 ;
39
+ const HEADER_ADDR : u64 = 0x100 ;
40
+ const HEADER_LEN : u32 = mem:: size_of :: < FuzzingBlkRequestHdr > ( ) as u32 ;
41
+ const REQ_DATA_ADDRS : & [ u64 ] = & [ 0x3000 , 0x4000 ] ;
42
+ const REQ_STATUS_ADDR : u64 = 0x5000 ;
43
+ const DESC_LEN : usize = 0x1000 ;
44
+
45
+ #[ test]
46
+ fn test_blk_basic_descriptor_chain ( ) {
47
+ let mem = GuestMemoryMmap :: < ( ) > :: from_ranges ( & [ ( GuestAddress ( 0 ) , 0x10000 ) ] ) . unwrap ( ) ;
48
+ let vq = MockSplitQueue :: new ( & mem, DEFAULT_QUEUE_SIZE ) ;
49
+
50
+ // Create header and write it to memory
51
+ let header = FuzzingBlkRequestHdr {
52
+ request_type : REQ_TYPE ,
53
+ _reserved : 0 ,
54
+ sector : REQ_SECTOR ,
55
+ } ;
56
+ mem. write_slice ( header. as_slice ( ) , GuestAddress ( HEADER_ADDR ) )
57
+ . unwrap ( ) ;
58
+
59
+ // Initialize data and status memory
60
+ for data_addr in REQ_DATA_ADDRS . iter ( ) . copied ( ) {
61
+ mem. write_slice ( & [ 0u8 ; DESC_LEN ] , GuestAddress ( data_addr) )
62
+ . unwrap ( ) ;
63
+ }
64
+ mem. write_slice ( & [ 0u8 ; DESC_LEN ] , GuestAddress ( REQ_STATUS_ADDR ) )
65
+ . unwrap ( ) ;
66
+
67
+ let descriptors = [
68
+ FuzzingDescriptor {
69
+ addr : HEADER_ADDR ,
70
+ len : HEADER_LEN ,
71
+ flags : VRING_DESC_F_NEXT as u16 ,
72
+ next : 1 ,
73
+ } ,
74
+ FuzzingDescriptor {
75
+ addr : REQ_DATA_ADDRS [ 0 ] ,
76
+ len : DESC_LEN as u32 ,
77
+ flags : ( VRING_DESC_F_NEXT | VRING_DESC_F_WRITE ) as u16 ,
78
+ next : 2 ,
79
+ } ,
80
+ FuzzingDescriptor {
81
+ addr : REQ_DATA_ADDRS [ 1 ] ,
82
+ len : DESC_LEN as u32 ,
83
+ flags : ( VRING_DESC_F_NEXT | VRING_DESC_F_WRITE ) as u16 ,
84
+ next : 3 ,
85
+ } ,
86
+ FuzzingDescriptor {
87
+ addr : REQ_STATUS_ADDR ,
88
+ len : DESC_LEN as u32 ,
89
+ flags : VRING_DESC_F_WRITE as u16 ,
90
+ next : 0 ,
91
+ } ,
92
+ ] ;
93
+
94
+ let q_descriptors: Vec < Descriptor > =
95
+ descriptors. into_iter ( ) . map ( |desc| desc. into ( ) ) . collect ( ) ;
96
+ let mut chain = vq. build_multiple_desc_chains ( & q_descriptors) . unwrap ( ) ;
97
+
98
+ let req = Request :: parse ( & mut chain) . unwrap ( ) ;
99
+ let data = req. data ( ) ;
100
+ assert_eq ! ( data. len( ) , 2 ) ;
101
+ assert_eq ! (
102
+ data. get( 0 ) ,
103
+ Some ( & ( GuestAddress ( REQ_DATA_ADDRS [ 0 ] ) , DESC_LEN as u32 ) )
104
+ ) ;
105
+ assert_eq ! (
106
+ data. get( 1 ) ,
107
+ Some ( & ( GuestAddress ( REQ_DATA_ADDRS [ 1 ] ) , DESC_LEN as u32 ) )
108
+ ) ;
109
+ assert_eq ! ( req. sector( ) , REQ_SECTOR ) ;
110
+ assert_eq ! ( req. status_addr( ) , GuestAddress ( REQ_STATUS_ADDR ) ) ;
111
+ assert_eq ! (
112
+ req. total_data_len( ) ,
113
+ ( DESC_LEN * REQ_DATA_ADDRS . len( ) ) as u64
114
+ ) ;
115
+ assert_eq ! ( req. request_type( ) , RequestType :: In ) ;
116
+
117
+ let fuzz_input = BlkInput {
118
+ descriptors : descriptors. to_vec ( ) ,
119
+ guestmem : Vec :: new ( ) ,
120
+ features : 0 ,
121
+ device_id : Some ( [ 1 ; 20 ] ) ,
122
+ } ;
123
+
124
+ let ( mut out_file, path) = create_corpus_file ( "blk" , "descriptor_chain" ) ;
125
+ out_file
126
+ . write_all ( bincode:: serialize ( & fuzz_input) . unwrap ( ) . as_slice ( ) )
127
+ . unwrap ( ) ;
128
+
129
+ // Let's validate that we have in the file what we actually wrote.
130
+ let written_input =
131
+ bincode:: deserialize :: < BlkInput > ( & std:: fs:: read ( path) . unwrap ( ) ) . unwrap ( ) ;
132
+ assert_eq ! ( fuzz_input, written_input) ;
133
+ }
134
+ }
0 commit comments