• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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