diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index f577fa4cd..3f5f771ad 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -178,6 +178,7 @@ version = "0.0.0" dependencies = [ "block_util", "cloud-hypervisor", + "devices", "libc", "libfuzzer-sys", "qcow", @@ -185,6 +186,7 @@ dependencies = [ "vhdx", "virtio-devices", "virtio-queue", + "vm-device", "vm-memory", "vm-virtio", "vmm-sys-util", diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index b08f0f911..a502b8b75 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -10,6 +10,7 @@ cargo-fuzz = true [dependencies] block_util = { path = "../block_util" } +devices = { path = "../devices" } libc = "0.2.126" libfuzzer-sys = "0.4.3" qcow = { path = "../qcow" } @@ -18,8 +19,9 @@ vhdx = { path = "../vhdx" } virtio-devices = { path = "../virtio-devices" } virtio-queue = "0.4.0" vmm-sys-util = "0.10.0" -vm-virtio = { path = "../vm-virtio" } vm-memory = "0.8.0" +vm-device = { path = "../vm-device" } +vm-virtio = { path = "../vm-virtio" } [dependencies.cloud-hypervisor] path = ".." @@ -50,3 +52,9 @@ name = "vhdx" path = "fuzz_targets/vhdx.rs" test = false doc = false + +[[bin]] +name = "serial" +path = "fuzz_targets/serial.rs" +test = false +doc = false diff --git a/fuzz/fuzz_targets/serial.rs b/fuzz/fuzz_targets/serial.rs new file mode 100644 index 000000000..1648c26c3 --- /dev/null +++ b/fuzz/fuzz_targets/serial.rs @@ -0,0 +1,73 @@ +// Copyright © 2022 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +#![no_main] +use devices::legacy::Serial; +use libc::EFD_NONBLOCK; +use libfuzzer_sys::fuzz_target; +use std::sync::Arc; +use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig, InterruptSourceGroup}; +use vm_device::BusDevice; +use vmm_sys_util::eventfd::EventFd; + +fuzz_target!(|bytes| { + let mut serial = Serial::new_sink( + "serial".into(), + Arc::new(TestInterrupt::new(EventFd::new(EFD_NONBLOCK).unwrap())), + ); + + let mut i = 0; + while i < bytes.len() { + let choice = bytes.get(i).unwrap_or(&0) % 3; + i += 1; + + match choice { + 0 => { + let offset = (bytes.get(i).unwrap_or(&0) % 8) as u64; + i += 1; + let mut out_bytes = vec![0]; + serial.read(0, offset, &mut out_bytes); + } + 1 => { + let offset = (bytes.get(i).unwrap_or(&0) % 8) as u64; + i += 1; + let data = vec![*bytes.get(i).unwrap_or(&0)]; + i += 1; + serial.write(0, offset, &data); + } + _ => { + let data = vec![*bytes.get(i).unwrap_or(&0)]; + i += 1; + serial.queue_input_bytes(&data).ok(); + } + } + } +}); + +struct TestInterrupt { + event_fd: EventFd, +} + +impl InterruptSourceGroup for TestInterrupt { + fn trigger(&self, _index: InterruptIndex) -> Result<(), std::io::Error> { + self.event_fd.write(1) + } + fn update( + &self, + _index: InterruptIndex, + _config: InterruptSourceConfig, + _masked: bool, + ) -> Result<(), std::io::Error> { + Ok(()) + } + fn notifier(&self, _index: InterruptIndex) -> Option { + Some(self.event_fd.try_clone().unwrap()) + } +} + +impl TestInterrupt { + fn new(event_fd: EventFd) -> Self { + TestInterrupt { event_fd } + } +}