Skip to content

Commit 121c4e0

Browse files
00xcepilys
authored andcommitted
fuzz: virtio-blk: add test
Add a simple test for the virtio-blk fuzz target, testing the basic functionality of the descriptor chain reassembly. Signed-off-by: Carlos López <[email protected]>
1 parent 23be8dd commit 121c4e0

File tree

1 file changed

+124
-0
lines changed

1 file changed

+124
-0
lines changed

fuzz/common/src/blk.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,127 @@ pub struct BlkInput {
88
pub features: u64,
99
pub device_id: Option<[u8; 20]>,
1010
}
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

Comments
 (0)