1 // Copyright 2018 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #![cfg(not(test))]
6 #![no_main]
7
8 use std::io::Cursor;
9 use std::io::Read;
10 use std::io::Seek;
11 use std::io::SeekFrom;
12 use std::mem::size_of;
13
14 use base::Event;
15 use cros_fuzz::fuzz_target;
16 use devices::virtio::base_features;
17 use devices::virtio::BlockAsync;
18 use devices::virtio::Interrupt;
19 use devices::virtio::Queue;
20 use devices::virtio::VirtioDevice;
21 use devices::IrqLevelEvent;
22 use hypervisor::ProtectionType;
23 use vm_memory::GuestAddress;
24 use vm_memory::GuestMemory;
25
26 const MEM_SIZE: u64 = 256 * 1024 * 1024;
27 const DESC_SIZE: u64 = 16; // Bytes in one virtio descriptor.
28 const QUEUE_SIZE: u16 = 16; // Max entries in the queue.
29 const CMD_SIZE: usize = 16; // Bytes in the command.
30
31 fuzz_target!(|bytes| {
32 let size_u64 = size_of::<u64>();
33 let mem = GuestMemory::new(&[(GuestAddress(0), MEM_SIZE)]).unwrap();
34
35 // The fuzz data is interpreted as:
36 // starting index 8 bytes
37 // command location 8 bytes
38 // command 16 bytes
39 // descriptors circular buffer 16 bytes * 3
40 if bytes.len() < 4 * size_u64 {
41 // Need an index to start.
42 return;
43 }
44
45 let mut data_image = Cursor::new(bytes);
46
47 let first_index = read_u64(&mut data_image);
48 if first_index > MEM_SIZE / DESC_SIZE {
49 return;
50 }
51 let first_offset = first_index * DESC_SIZE;
52 if first_offset as usize + size_u64 > bytes.len() {
53 return;
54 }
55
56 let command_addr = read_u64(&mut data_image);
57 if command_addr > MEM_SIZE - CMD_SIZE as u64 {
58 return;
59 }
60 if mem
61 .write_all_at_addr(
62 &bytes[2 * size_u64..(2 * size_u64) + CMD_SIZE],
63 GuestAddress(command_addr as u64),
64 )
65 .is_err()
66 {
67 return;
68 }
69
70 data_image.seek(SeekFrom::Start(first_offset)).unwrap();
71 let desc_table = read_u64(&mut data_image);
72
73 if mem
74 .write_all_at_addr(&bytes[32..], GuestAddress(desc_table as u64))
75 .is_err()
76 {
77 return;
78 }
79
80 let mut q = Queue::new(QUEUE_SIZE);
81 q.set_size(QUEUE_SIZE / 2);
82 q.set_ready(true);
83
84 let queue_evt = Event::new().unwrap();
85
86 let features = base_features(ProtectionType::Unprotected);
87
88 let disk_file = tempfile::tempfile().unwrap();
89 let mut block = BlockAsync::new(
90 features,
91 Box::new(disk_file),
92 false,
93 true,
94 512,
95 false,
96 None,
97 None,
98 None,
99 None,
100 None,
101 )
102 .unwrap();
103
104 block
105 .activate(
106 mem,
107 Interrupt::new(
108 IrqLevelEvent::new().unwrap(),
109 None, // msix_config
110 0xFFFF, // VIRTIO_MSI_NO_VECTOR
111 ),
112 vec![(q, queue_evt.try_clone().unwrap())],
113 )
114 .unwrap();
115
116 queue_evt.signal().unwrap(); // Rings the doorbell
117 });
118
read_u64<T: Read>(readable: &mut T) -> u64119 fn read_u64<T: Read>(readable: &mut T) -> u64 {
120 let mut buf = [0u8; size_of::<u64>()];
121 readable.read_exact(&mut buf[..]).unwrap();
122 u64::from_le_bytes(buf)
123 }
124