crosvm/fuzz/block_fuzzer.rs
Daniel Verkamp 4e1f99a68d devices: virtio: block: add VIRTIO_BLK_T_GET_ID
Allow the user to specify a serial number for each virtio block device
using the new id= parameter:

  crosvm run --disk disk.img,id=SERIALNO ...

These serial numbers show up in sysfs for each block device, which
allows them to be uniquely identified regardless of the number or order
of block devices added on the crosvm command line.  This can be used to
find a specific device by serial number for mounting at boot time.

BUG=b:157687637
BUG=chromium:775781
TEST=crosvm run -r vm_rootfs.img,id=root -p init=/bin/bash vm_kernel
TEST=cat /sys/block/vda/serial # see serial is set to "root"
TEST=cargo test -p devices

Change-Id: I108cdc47c367fb038d6acd55da60f9e1aae59e68
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2225559
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
Commit-Queue: Daniel Verkamp <dverkamp@chromium.org>
2020-12-02 05:21:16 +00:00

107 lines
2.9 KiB
Rust

// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#![no_main]
use std::io::{Cursor, Read, Seek, SeekFrom};
use std::mem::size_of;
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;
use base::Event;
use cros_fuzz::fuzz_target;
use devices::virtio::{base_features, Block, Interrupt, Queue, VirtioDevice};
use tempfile;
use vm_memory::{GuestAddress, GuestMemory};
const MEM_SIZE: u64 = 256 * 1024 * 1024;
const DESC_SIZE: u64 = 16; // Bytes in one virtio descriptor.
const QUEUE_SIZE: u16 = 16; // Max entries in the queue.
const CMD_SIZE: usize = 16; // Bytes in the command.
fuzz_target!(|bytes| {
let size_u64 = size_of::<u64>();
let mem = GuestMemory::new(&[(GuestAddress(0), MEM_SIZE)]).unwrap();
// The fuzz data is interpreted as:
// starting index 8 bytes
// command location 8 bytes
// command 16 bytes
// descriptors circular buffer 16 bytes * 3
if bytes.len() < 4 * size_u64 {
// Need an index to start.
return;
}
let mut data_image = Cursor::new(bytes);
let first_index = read_u64(&mut data_image);
if first_index > MEM_SIZE / DESC_SIZE {
return;
}
let first_offset = first_index * DESC_SIZE;
if first_offset as usize + size_u64 > bytes.len() {
return;
}
let command_addr = read_u64(&mut data_image);
if command_addr > MEM_SIZE - CMD_SIZE as u64 {
return;
}
if mem
.write_all_at_addr(
&bytes[2 * size_u64..(2 * size_u64) + CMD_SIZE],
GuestAddress(command_addr as u64),
)
.is_err()
{
return;
}
data_image.seek(SeekFrom::Start(first_offset)).unwrap();
let desc_table = read_u64(&mut data_image);
if mem
.write_all_at_addr(&bytes[32..], GuestAddress(desc_table as u64))
.is_err()
{
return;
}
let mut q = Queue::new(QUEUE_SIZE);
q.ready = true;
q.size = QUEUE_SIZE / 2;
q.max_size = QUEUE_SIZE;
let queue_evts: Vec<Event> = vec![Event::new().unwrap()];
let queue_evt = queue_evts[0].try_clone().unwrap();
let features = base_features(false);
let disk_file = tempfile::tempfile().unwrap();
let mut block =
Block::new(features, Box::new(disk_file), false, true, 512, None, None).unwrap();
block.activate(
mem,
Interrupt::new(
Arc::new(AtomicUsize::new(0)),
Event::new().unwrap(),
Event::new().unwrap(),
None, // msix_config
0xFFFF, // VIRTIO_MSI_NO_VECTOR
),
vec![q],
queue_evts,
);
queue_evt.write(77).unwrap(); // Rings the doorbell, any byte will do.
});
fn read_u64<T: Read>(readable: &mut T) -> u64 {
let mut buf = [0u8; size_of::<u64>()];
readable.read_exact(&mut buf[..]).unwrap();
u64::from_le_bytes(buf)
}