diff --git a/fuzz/.gitignore b/fuzz/.gitignore new file mode 100644 index 0000000000..1a45eee776 --- /dev/null +++ b/fuzz/.gitignore @@ -0,0 +1,4 @@ +target +corpus +artifacts +coverage diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock new file mode 100644 index 0000000000..e2bd515772 --- /dev/null +++ b/fuzz/Cargo.lock @@ -0,0 +1,150 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arbitrary" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" + +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "jobserver" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.148" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "packit" +version = "0.1.0" +source = "git+https://github.com/coconut-svsm/packit#fffebdc18a3f559f0a01425b17cf41b1c249fbe0" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "svsm" +version = "0.1.0" +dependencies = [ + "bitflags", + "log", + "packit", +] + +[[package]] +name = "svsm-fuzz" +version = "0.0.0" +dependencies = [ + "libfuzzer-sys", + "svsm", +] + +[[package]] +name = "syn" +version = "2.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "zerocopy" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20707b61725734c595e840fb3704378a0cd2b9c74cc9e6e20724838fc6a1e2f9" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56097d5b91d711293a42be9289403896b68654625021732067eac7a4ca388a1f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml new file mode 100644 index 0000000000..8c3d168b6b --- /dev/null +++ b/fuzz/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "svsm-fuzz" +version = "0.0.0" +publish = false +edition = "2021" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = "0.4" + +[dependencies.svsm] +path = ".." + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[profile.release] +debug = 1 + +[[bin]] +name = "fw_meta" +path = "fuzz_targets/fw_meta.rs" +test = false +doc = false + +[[bin]] +name = "acpi" +path = "fuzz_targets/acpi.rs" +test = false +doc = false diff --git a/fuzz/acpi-dict.txt b/fuzz/acpi-dict.txt new file mode 100644 index 0000000000..c20a7e0bf4 --- /dev/null +++ b/fuzz/acpi-dict.txt @@ -0,0 +1,4 @@ +"etc/acpi/rsdp" +"etc/acpi/tables" +"APIC" +"\x00\x00\x00\x14" diff --git a/fuzz/fuzz_targets/acpi.rs b/fuzz/fuzz_targets/acpi.rs new file mode 100644 index 0000000000..54d3a95a38 --- /dev/null +++ b/fuzz/fuzz_targets/acpi.rs @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022-2023 SUSE LLC +// +// Author: Carlos López + +#![no_main] + +use core::num::NonZeroUsize; +use libfuzzer_sys::{fuzz_target, Corpus}; +use std::cell::Cell; +use std::hint::black_box; +use svsm::acpi::tables::load_acpi_cpu_info; +use svsm::fw_cfg::FwCfg; +use svsm::io::IOPort; + +/// A structure that emulates port I/O from a libfuzzer input. +#[derive(Clone, Debug)] +struct FuzzIo<'a> { + data: &'a [u8], + len: NonZeroUsize, + pos: Cell, +} + +impl<'a> FuzzIo<'a> { + /// Create a new [`FuzzIo`] instance. Returns [`None`] if the input is + /// empty. + fn new(data: &'a [u8]) -> Option { + let len = NonZeroUsize::new(data.len())?; + let pos = Cell::new(0); + Some(Self { data, len, pos }) + } +} + +impl IOPort for FuzzIo<'_> { + fn outb(&self, _port: u16, _value: u8) {} + fn outw(&self, _port: u16, _value: u16) {} + + fn inb(&self, _port: u16) -> u8 { + let pos = self.pos.get(); + let val = unsafe { *self.data.get_unchecked(pos) }; + self.pos.set((pos + 1) % self.len); + val + } + + fn inw(&self, port: u16) -> u16 { + let mut buf = [0u8; 2]; + buf[0] = self.inb(port); + buf[1] = self.inb(port); + u16::from_le_bytes(buf) + } +} + +fuzz_target!(|data: &[u8]| -> Corpus { + let Some(io) = FuzzIo::new(data) else { + return Corpus::Reject; + }; + let fwcfg = FwCfg::new(&io); + + if let Ok(info) = load_acpi_cpu_info(&fwcfg) { + let _ = black_box(info); + } + + Corpus::Keep +}); diff --git a/fuzz/fuzz_targets/fw_meta.rs b/fuzz/fuzz_targets/fw_meta.rs new file mode 100644 index 0000000000..bb624ab97f --- /dev/null +++ b/fuzz/fuzz_targets/fw_meta.rs @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022-2023 SUSE LLC +// +// Author: Carlos López + +#![no_main] + +use libfuzzer_sys::{fuzz_target, Corpus}; +use std::hint::black_box; +use svsm::address::VirtAddr; +use svsm::fw_meta::parse_fw_meta_data; +use svsm::types::PAGE_SIZE; + +fuzz_target!(|data: &[u8]| -> Corpus { + if data.len() != PAGE_SIZE { + return Corpus::Reject; + } + + let addr = VirtAddr::from(data.as_ptr()); + let fw_meta = parse_fw_meta_data(addr); + if let Ok(meta) = fw_meta { + let _ = black_box(meta); + } + + Corpus::Keep +}); diff --git a/src/mm/alloc.rs b/src/mm/alloc.rs index e74e1be5e8..1076572807 100644 --- a/src/mm/alloc.rs +++ b/src/mm/alloc.rs @@ -1282,7 +1282,7 @@ unsafe impl GlobalAlloc for SvsmAllocator { } } -#[cfg_attr(not(any(test, doctest)), global_allocator)] +#[cfg_attr(not(any(test, doctest, fuzzing)), global_allocator)] pub static mut ALLOCATOR: SvsmAllocator = SvsmAllocator::new(); pub fn root_mem_init(pstart: PhysAddr, vstart: VirtAddr, page_count: usize) {