summary refs log tree commit diff
path: root/fuzz
diff options
context:
space:
mode:
authorDaniel Verkamp <dverkamp@chromium.org>2019-10-24 10:25:16 -0700
committerCommit Bot <commit-bot@chromium.org>2019-10-28 20:30:18 +0000
commitee723d5204f8a0741cf993900fb6471202db9a97 (patch)
treea6b9c09fd4f6997426aa83e48dc7af5a0bdfb443 /fuzz
parent46ab05d1e982d5d52df3243475fa09f91b89f7d6 (diff)
downloadcrosvm-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.rs164
-rw-r--r--fuzz/qcow_fuzzer.rs50
-rw-r--r--fuzz/usb_descriptor_fuzzer.rs22
-rw-r--r--fuzz/zimage_fuzzer.rs26
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);
+});