1 // Copyright 2019 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::Read; 9 use std::io::Write; 10 use std::mem::size_of; 11 12 use base::Event; 13 use crosvm_fuzz::fuzz_target; 14 use crosvm_fuzz::rand::FuzzRng; 15 use devices::virtio::QueueConfig; 16 use rand::Rng; 17 use rand::RngCore; 18 use vm_memory::GuestAddress; 19 use vm_memory::GuestMemory; 20 21 const MAX_QUEUE_SIZE: u16 = 256; 22 const MEM_SIZE: u64 = 1024 * 1024; 23 24 thread_local! { 25 static GUEST_MEM: GuestMemory = GuestMemory::new(&[(GuestAddress(0), MEM_SIZE)]).unwrap(); 26 } 27 28 // These are taken from the virtio spec and can be used as a reference for the size calculations in 29 // the fuzzer. 30 #[repr(C, packed)] 31 struct virtq_desc { 32 addr: u64, 33 len: u32, 34 flags: u16, 35 next: u16, 36 } 37 38 #[repr(C, packed)] 39 struct virtq_avail { 40 flags: u16, 41 idx: u16, 42 ring: [u16; MAX_QUEUE_SIZE as usize], 43 used_event: u16, 44 } 45 46 #[repr(C, packed)] 47 struct virtq_used_elem { 48 id: u32, 49 len: u32, 50 } 51 52 #[repr(C, packed)] 53 struct virtq_used { 54 flags: u16, 55 idx: u16, 56 ring: [virtq_used_elem; MAX_QUEUE_SIZE as usize], 57 avail_event: u16, 58 } 59 60 fuzz_target!(|data: &[u8]| { 61 let mut q = QueueConfig::new(MAX_QUEUE_SIZE, 0); 62 let mut rng = FuzzRng::new(data); 63 q.set_size(rng.gen()); 64 65 // For each of {desc_table,avail_ring,used_ring} generate a random address that includes enough 66 // space to hold the relevant struct with the largest possible queue size. 67 let max_table_size = MAX_QUEUE_SIZE as u64 * size_of::<virtq_desc>() as u64; 68 q.set_desc_table(GuestAddress(rng.gen_range(0..MEM_SIZE - max_table_size))); 69 q.set_avail_ring(GuestAddress( 70 rng.gen_range(0..MEM_SIZE - size_of::<virtq_avail>() as u64), 71 )); 72 q.set_used_ring(GuestAddress( 73 rng.gen_range(0..MEM_SIZE - size_of::<virtq_used>() as u64), 74 )); 75 q.set_ready(true); 76 77 GUEST_MEM.with(|mem| { 78 let mut q = if let Ok(q) = q.activate(mem, Event::new().unwrap()) { 79 q 80 } else { 81 return; 82 }; 83 84 // First zero out all of the memory. 85 let vs = mem 86 .get_slice_at_addr(GuestAddress(0), MEM_SIZE as usize) 87 .unwrap(); 88 vs.write_bytes(0); 89 90 // Fill in the descriptor table. 91 let queue_size = q.size() as usize; 92 let mut buf = vec![0u8; queue_size * size_of::<virtq_desc>()]; 93 94 rng.fill_bytes(&mut buf[..]); 95 mem.write_all_at_addr(&buf[..], q.desc_table()).unwrap(); 96 97 // Fill in the available ring. See the definition of virtq_avail above for the source of 98 // these numbers. 99 let avail_size = 4 + (queue_size * 2) + 2; 100 buf.resize(avail_size, 0); 101 rng.fill_bytes(&mut buf[..]); 102 mem.write_all_at_addr(&buf[..], q.avail_ring()).unwrap(); 103 104 // Fill in the used ring. See the definition of virtq_used above for the source of 105 // these numbers. 106 let used_size = 4 + (queue_size * size_of::<virtq_used_elem>()) + 2; 107 buf.resize(used_size, 0); 108 rng.fill_bytes(&mut buf[..]); 109 mem.write_all_at_addr(&buf[..], q.used_ring()).unwrap(); 110 111 while let Some(mut avail_desc) = q.pop() { 112 // Read the entire readable portion of the buffer. 113 let mut read_buf = vec![0u8; avail_desc.reader.available_bytes()]; 114 avail_desc.reader.read_exact(&mut read_buf).unwrap(); 115 116 // Write the entire writable portion of the buffer. 117 let write_buf = vec![0u8; avail_desc.writer.available_bytes()]; 118 avail_desc.writer.write_all(&write_buf).unwrap(); 119 120 let bytes_written = avail_desc.writer.bytes_written() as u32; 121 q.add_used(avail_desc, bytes_written); 122 } 123 }); 124 }); 125