diff options
author | Daniel Verkamp <dverkamp@chromium.org> | 2019-10-24 10:25:16 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-10-28 20:30:18 +0000 |
commit | ee723d5204f8a0741cf993900fb6471202db9a97 (patch) | |
tree | a6b9c09fd4f6997426aa83e48dc7af5a0bdfb443 /fuzz | |
parent | 46ab05d1e982d5d52df3243475fa09f91b89f7d6 (diff) | |
download | crosvm-ee723d5204f8a0741cf993900fb6471202db9a97.tar crosvm-ee723d5204f8a0741cf993900fb6471202db9a97.tar.gz crosvm-ee723d5204f8a0741cf993900fb6471202db9a97.tar.bz2 crosvm-ee723d5204f8a0741cf993900fb6471202db9a97.tar.lz crosvm-ee723d5204f8a0741cf993900fb6471202db9a97.tar.xz crosvm-ee723d5204f8a0741cf993900fb6471202db9a97.tar.zst crosvm-ee723d5204f8a0741cf993900fb6471202db9a97.zip |
fuzz: convert fuzzers to cros_fuzz framework
This eliminates the boilerplate for catching panics and creating a Rust slice from the fuzzer input data. BUG=None TEST=`USE='asan fuzzer' emerge-nami crosvm` Change-Id: I49666a344b02e3333ad6823bfa7dace08b66b290 Signed-off-by: Daniel Verkamp <dverkamp@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1879495 Reviewed-by: Dylan Reid <dgreid@chromium.org>
Diffstat (limited to 'fuzz')
-rw-r--r-- | fuzz/block_fuzzer.rs | 164 | ||||
-rw-r--r-- | fuzz/qcow_fuzzer.rs | 50 | ||||
-rw-r--r-- | fuzz/usb_descriptor_fuzzer.rs | 22 | ||||
-rw-r--r-- | fuzz/zimage_fuzzer.rs | 26 |
4 files changed, 103 insertions, 159 deletions
diff --git a/fuzz/block_fuzzer.rs b/fuzz/block_fuzzer.rs index a25c249..b1bc003 100644 --- a/fuzz/block_fuzzer.rs +++ b/fuzz/block_fuzzer.rs @@ -8,12 +8,10 @@ use std::fs::File; use std::io::{Cursor, Read, Seek, SeekFrom}; use std::mem::size_of; use std::os::unix::io::{AsRawFd, FromRawFd}; -use std::panic; -use std::process; -use std::slice; use std::sync::atomic::AtomicUsize; use std::sync::Arc; +use cros_fuzz::fuzz_target; use devices::virtio::{Block, Queue, VirtioDevice}; use sys_util::{EventFd, GuestAddress, GuestMemory, SharedMemory}; @@ -22,92 +20,80 @@ 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. -#[export_name = "LLVMFuzzerTestOneInput"] -pub fn test_one_input(data: *const u8, size: usize) -> i32 { - // We cannot unwind past ffi boundaries. - panic::catch_unwind(|| { - // Safe because the libfuzzer runtime will guarantee that `data` is at least - // `size` bytes long and that it will be valid for the lifetime of this - // function. - let bytes = unsafe { slice::from_raw_parts(data, size) }; - 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<EventFd> = vec![EventFd::new().unwrap()]; - let queue_fd = queue_evts[0].as_raw_fd(); - let queue_evt = unsafe { EventFd::from_raw_fd(libc::dup(queue_fd)) }; - - let shm = SharedMemory::anon().unwrap(); - let disk_file: File = shm.into(); - let mut block = Block::new(Box::new(disk_file), false, None).unwrap(); - - block.activate( - mem, - EventFd::new().unwrap(), - EventFd::new().unwrap(), - None, // msix_config - Arc::new(AtomicUsize::new(0)), - vec![q], - queue_evts, - ); - - queue_evt.write(77).unwrap(); // Rings the doorbell, any byte will do. - }) - .err() - .map(|_| process::abort()); - - 0 -} +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<EventFd> = vec![EventFd::new().unwrap()]; + let queue_fd = queue_evts[0].as_raw_fd(); + let queue_evt = unsafe { EventFd::from_raw_fd(libc::dup(queue_fd)) }; + + let shm = SharedMemory::anon().unwrap(); + let disk_file: File = shm.into(); + let mut block = Block::new(Box::new(disk_file), false, None).unwrap(); + + block.activate( + mem, + EventFd::new().unwrap(), + EventFd::new().unwrap(), + None, // msix_config + Arc::new(AtomicUsize::new(0)), + 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>()]; diff --git a/fuzz/qcow_fuzzer.rs b/fuzz/qcow_fuzzer.rs index f76e5d0..74bc75f 100644 --- a/fuzz/qcow_fuzzer.rs +++ b/fuzz/qcow_fuzzer.rs @@ -4,48 +4,34 @@ #![no_main] +use cros_fuzz::fuzz_target; use qcow::QcowFile; use sys_util::SharedMemory; use std::fs::File; use std::io::{Cursor, Read, Seek, SeekFrom, Write}; use std::mem::size_of; -use std::panic; -use std::process; -use std::slice; // Take the first 64 bits of data as an address and the next 64 bits as data to // store there. The rest of the data is used as a qcow image. -#[export_name = "LLVMFuzzerTestOneInput"] -pub fn test_one_input(data: *const u8, size: usize) -> i32 { - // We cannot unwind past ffi boundaries. - panic::catch_unwind(|| { - // Safe because the libfuzzer runtime will guarantee that `data` is at least - // `size` bytes long and that it will be valid for the lifetime of this - // function. - let bytes = unsafe { slice::from_raw_parts(data, size) }; - if bytes.len() < 16 { - // Need an address and data, each are 8 bytes. - return; +fuzz_target!(|bytes| { + if bytes.len() < 16 { + // Need an address and data, each are 8 bytes. + return; + } + let mut disk_image = Cursor::new(bytes); + let addr = read_u64(&mut disk_image); + let value = read_u64(&mut disk_image); + let shm = SharedMemory::anon().unwrap(); + let mut disk_file: File = shm.into(); + disk_file.write_all(&bytes[16..]).unwrap(); + disk_file.seek(SeekFrom::Start(0)).unwrap(); + if let Ok(mut qcow) = QcowFile::from(disk_file) { + if qcow.seek(SeekFrom::Start(addr)).is_ok() { + let _ = qcow.write_all(&value.to_le_bytes()); } - let mut disk_image = Cursor::new(bytes); - let addr = read_u64(&mut disk_image); - let value = read_u64(&mut disk_image); - let shm = SharedMemory::anon().unwrap(); - let mut disk_file: File = shm.into(); - disk_file.write_all(&bytes[16..]).unwrap(); - disk_file.seek(SeekFrom::Start(0)).unwrap(); - if let Ok(mut qcow) = QcowFile::from(disk_file) { - if qcow.seek(SeekFrom::Start(addr)).is_ok() { - let _ = qcow.write_all(&value.to_le_bytes()); - } - } - }) - .err() - .map(|_| process::abort()); - - 0 -} + } +}); fn read_u64<T: Read>(readable: &mut T) -> u64 { let mut buf = [0u8; size_of::<u64>()]; diff --git a/fuzz/usb_descriptor_fuzzer.rs b/fuzz/usb_descriptor_fuzzer.rs index d78c8c5..a33e7c7 100644 --- a/fuzz/usb_descriptor_fuzzer.rs +++ b/fuzz/usb_descriptor_fuzzer.rs @@ -4,24 +4,10 @@ #![no_main] -use std::panic; -use std::process; -use std::slice; +use cros_fuzz::fuzz_target; use usb_util::parse_usbfs_descriptors; -#[export_name = "LLVMFuzzerTestOneInput"] -pub fn test_one_input(data: *const u8, size: usize) -> i32 { - // We cannot unwind past ffi boundaries. - panic::catch_unwind(|| { - // Safe because the libfuzzer runtime will guarantee that `data` is at least - // `size` bytes long and that it will be valid for the lifetime of this - // function. - let bytes = unsafe { slice::from_raw_parts(data, size) }; - let _ = parse_usbfs_descriptors(bytes); - }) - .err() - .map(|_| process::abort()); - - 0 -} +fuzz_target!(|data| { + let _ = parse_usbfs_descriptors(data); +}); diff --git a/fuzz/zimage_fuzzer.rs b/fuzz/zimage_fuzzer.rs index 0cc41cf..971e750 100644 --- a/fuzz/zimage_fuzzer.rs +++ b/fuzz/zimage_fuzzer.rs @@ -4,13 +4,11 @@ #![no_main] +use cros_fuzz::fuzz_target; use sys_util::{GuestAddress, GuestMemory, SharedMemory}; use std::fs::File; use std::io::Write; -use std::panic; -use std::process; -use std::slice; const MEM_SIZE: u64 = 256 * 1024 * 1024; @@ -23,20 +21,8 @@ fn make_elf_bin(elf_bytes: &[u8]) -> File { shm.into() } -#[export_name = "LLVMFuzzerTestOneInput"] -pub fn test_one_input(data: *const u8, size: usize) -> i32 { - // We cannot unwind past ffi boundaries. - panic::catch_unwind(|| { - // Safe because the libfuzzer runtime will guarantee that `data` is at least - // `size` bytes long and that it will be valid for the lifetime of this - // function. - let bytes = unsafe { slice::from_raw_parts(data, size) }; - let mut kimage = make_elf_bin(bytes); - let mem = GuestMemory::new(&[(GuestAddress(0), MEM_SIZE)]).unwrap(); - let _ = kernel_loader::load_kernel(&mem, GuestAddress(0), &mut kimage); - }) - .err() - .map(|_| process::abort()); - - 0 -} +fuzz_target!(|bytes| { + let mut kimage = make_elf_bin(bytes); + let mem = GuestMemory::new(&[(GuestAddress(0), MEM_SIZE)]).unwrap(); + let _ = kernel_loader::load_kernel(&mem, GuestAddress(0), &mut kimage); +}); |