mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-08-22 07:51:16 +00:00
These Default implementations either don't produce valid configs, are no longer used outside of tests, or both. For the tests, we can define our own local "default" values that make the most sense for the tests, without worrying about what's a (somewhat) sensible "global" default value. Signed-off-by: Alyssa Ross <hi@alyssa.is>
314 lines
9.0 KiB
Rust
314 lines
9.0 KiB
Rust
// Copyright © 2022 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
#![no_main]
|
|
use libfuzzer_sys::fuzz_target;
|
|
use micro_http::Request;
|
|
use once_cell::sync::Lazy;
|
|
use std::os::unix::io::AsRawFd;
|
|
use std::path::PathBuf;
|
|
use std::sync::mpsc::{channel, Receiver};
|
|
use std::sync::{Arc, Mutex};
|
|
use std::thread;
|
|
use vm_migration::MigratableError;
|
|
use vmm::api::{
|
|
http::*, ApiRequest, RequestHandler, VmInfoResponse, VmReceiveMigrationData,
|
|
VmSendMigrationData, VmmPingResponse,
|
|
};
|
|
use vmm::config::RestoreConfig;
|
|
use vmm::vm::{Error as VmError, VmState};
|
|
use vmm::vm_config::*;
|
|
use vmm::{EpollContext, EpollDispatch};
|
|
use vmm_sys_util::eventfd::EventFd;
|
|
|
|
// Need to be ordered for test case reproducibility
|
|
static ROUTES: Lazy<Vec<&Box<dyn EndpointHandler + Sync + Send>>> =
|
|
Lazy::new(|| HTTP_ROUTES.routes.values().collect());
|
|
|
|
fuzz_target!(|bytes| {
|
|
if bytes.len() < 2 {
|
|
return;
|
|
}
|
|
|
|
let route = ROUTES[bytes[0] as usize % ROUTES.len()];
|
|
if let Some(request) = generate_request(&bytes[1..]) {
|
|
let exit_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
|
|
let api_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
|
|
let (api_sender, api_receiver) = channel();
|
|
|
|
let http_receiver_thread = {
|
|
let exit_evt = exit_evt.try_clone().unwrap();
|
|
let api_evt = api_evt.try_clone().unwrap();
|
|
thread::Builder::new()
|
|
.name("http_receiver".to_string())
|
|
.spawn(move || {
|
|
http_receiver_stub(exit_evt, api_evt, api_receiver);
|
|
})
|
|
.unwrap()
|
|
};
|
|
|
|
route.handle_request(&request, api_evt, api_sender);
|
|
exit_evt.write(1).ok();
|
|
http_receiver_thread.join().unwrap();
|
|
};
|
|
});
|
|
|
|
fn generate_request(bytes: &[u8]) -> Option<Request> {
|
|
let req_method = match bytes[0] % 5 {
|
|
0 => "GET",
|
|
1 => "PUT",
|
|
2 => "PATCH",
|
|
3 => "POST",
|
|
_ => "INVALID",
|
|
};
|
|
let request_line = format!("{} http://localhost/home HTTP/1.1\r\n", req_method);
|
|
|
|
let req_body = &bytes[1..];
|
|
let request = if req_body.len() > 0 {
|
|
[
|
|
format!("{}Content-Length: {}\r\n", request_line, req_body.len()).as_bytes(),
|
|
req_body,
|
|
]
|
|
.concat()
|
|
} else {
|
|
format!("{}\r\n", request_line).as_bytes().to_vec()
|
|
};
|
|
|
|
Request::try_from(&request, None).ok()
|
|
}
|
|
|
|
struct StubApiRequestHandler;
|
|
|
|
impl RequestHandler for StubApiRequestHandler {
|
|
fn vm_create(&mut self, _: Arc<Mutex<VmConfig>>) -> Result<(), VmError> {
|
|
Ok(())
|
|
}
|
|
|
|
fn vm_boot(&mut self) -> Result<(), VmError> {
|
|
Ok(())
|
|
}
|
|
|
|
fn vm_pause(&mut self) -> Result<(), VmError> {
|
|
Ok(())
|
|
}
|
|
|
|
fn vm_resume(&mut self) -> Result<(), VmError> {
|
|
Ok(())
|
|
}
|
|
|
|
fn vm_snapshot(&mut self, _: &str) -> Result<(), VmError> {
|
|
Ok(())
|
|
}
|
|
|
|
fn vm_restore(&mut self, _: RestoreConfig) -> Result<(), VmError> {
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
|
fn vm_coredump(&mut self, _: &str) -> Result<(), VmError> {
|
|
Ok(())
|
|
}
|
|
|
|
fn vm_shutdown(&mut self) -> Result<(), VmError> {
|
|
Ok(())
|
|
}
|
|
|
|
fn vm_reboot(&mut self) -> Result<(), VmError> {
|
|
Ok(())
|
|
}
|
|
|
|
fn vm_info(&self) -> Result<VmInfoResponse, VmError> {
|
|
Ok(VmInfoResponse {
|
|
config: Arc::new(Mutex::new(VmConfig {
|
|
cpus: CpusConfig {
|
|
boot_vcpus: 1,
|
|
max_vcpus: 1,
|
|
topology: None,
|
|
kvm_hyperv: false,
|
|
max_phys_bits: 46,
|
|
affinity: None,
|
|
features: CpuFeatures::default(),
|
|
},
|
|
memory: MemoryConfig {
|
|
size: 536_870_912,
|
|
mergeable: false,
|
|
hotplug_method: HotplugMethod::Acpi,
|
|
hotplug_size: None,
|
|
hotplugged_size: None,
|
|
shared: false,
|
|
hugepages: false,
|
|
hugepage_size: None,
|
|
prefault: false,
|
|
zones: None,
|
|
thp: true,
|
|
},
|
|
payload: Some(PayloadConfig {
|
|
kernel: Some(PathBuf::from("/path/to/kernel")),
|
|
firmware: None,
|
|
cmdline: None,
|
|
initramfs: None,
|
|
#[cfg(feature = "igvm")]
|
|
igvm: None,
|
|
}),
|
|
rate_limit_groups: None,
|
|
disks: None,
|
|
net: None,
|
|
rng: RngConfig {
|
|
src: PathBuf::from("/dev/urandom"),
|
|
iommu: false,
|
|
},
|
|
balloon: None,
|
|
fs: None,
|
|
pmem: None,
|
|
serial: ConsoleConfig {
|
|
file: None,
|
|
mode: ConsoleOutputMode::Null,
|
|
iommu: false,
|
|
socket: None,
|
|
},
|
|
console: ConsoleConfig {
|
|
file: None,
|
|
mode: ConsoleOutputMode::Tty,
|
|
iommu: false,
|
|
socket: None,
|
|
},
|
|
devices: None,
|
|
user_devices: None,
|
|
vdpa: None,
|
|
vsock: None,
|
|
pvpanic: false,
|
|
iommu: false,
|
|
#[cfg(target_arch = "x86_64")]
|
|
sgx_epc: None,
|
|
numa: None,
|
|
watchdog: false,
|
|
#[cfg(feature = "guest_debug")]
|
|
gdb: false,
|
|
platform: None,
|
|
tpm: None,
|
|
preserved_fds: None,
|
|
})),
|
|
state: VmState::Running,
|
|
memory_actual_size: 0,
|
|
device_tree: None,
|
|
})
|
|
}
|
|
|
|
fn vmm_ping(&self) -> VmmPingResponse {
|
|
VmmPingResponse {
|
|
build_version: String::new(),
|
|
version: String::new(),
|
|
pid: 0,
|
|
features: Vec::new(),
|
|
}
|
|
}
|
|
|
|
fn vm_delete(&mut self) -> Result<(), VmError> {
|
|
Ok(())
|
|
}
|
|
|
|
fn vmm_shutdown(&mut self) -> Result<(), VmError> {
|
|
Ok(())
|
|
}
|
|
|
|
fn vm_resize(&mut self, _: Option<u8>, _: Option<u64>, _: Option<u64>) -> Result<(), VmError> {
|
|
Ok(())
|
|
}
|
|
|
|
fn vm_resize_zone(&mut self, _: String, _: u64) -> Result<(), VmError> {
|
|
Ok(())
|
|
}
|
|
|
|
fn vm_add_device(&mut self, _: DeviceConfig) -> Result<Option<Vec<u8>>, VmError> {
|
|
Ok(None)
|
|
}
|
|
|
|
fn vm_add_user_device(&mut self, _: UserDeviceConfig) -> Result<Option<Vec<u8>>, VmError> {
|
|
Ok(None)
|
|
}
|
|
|
|
fn vm_remove_device(&mut self, _: String) -> Result<(), VmError> {
|
|
Ok(())
|
|
}
|
|
|
|
fn vm_add_disk(&mut self, _: DiskConfig) -> Result<Option<Vec<u8>>, VmError> {
|
|
Ok(None)
|
|
}
|
|
|
|
fn vm_add_fs(&mut self, _: FsConfig) -> Result<Option<Vec<u8>>, VmError> {
|
|
Ok(None)
|
|
}
|
|
|
|
fn vm_add_pmem(&mut self, _: PmemConfig) -> Result<Option<Vec<u8>>, VmError> {
|
|
Ok(None)
|
|
}
|
|
|
|
fn vm_add_net(&mut self, _: NetConfig) -> Result<Option<Vec<u8>>, VmError> {
|
|
Ok(None)
|
|
}
|
|
|
|
fn vm_add_vdpa(&mut self, _: VdpaConfig) -> Result<Option<Vec<u8>>, VmError> {
|
|
Ok(None)
|
|
}
|
|
|
|
fn vm_add_vsock(&mut self, _: VsockConfig) -> Result<Option<Vec<u8>>, VmError> {
|
|
Ok(None)
|
|
}
|
|
|
|
fn vm_counters(&mut self) -> Result<Option<Vec<u8>>, VmError> {
|
|
Ok(None)
|
|
}
|
|
|
|
fn vm_power_button(&mut self) -> Result<(), VmError> {
|
|
Ok(())
|
|
}
|
|
|
|
fn vm_receive_migration(&mut self, _: VmReceiveMigrationData) -> Result<(), MigratableError> {
|
|
Ok(())
|
|
}
|
|
|
|
fn vm_send_migration(&mut self, _: VmSendMigrationData) -> Result<(), MigratableError> {
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
fn http_receiver_stub(exit_evt: EventFd, api_evt: EventFd, api_receiver: Receiver<ApiRequest>) {
|
|
let mut epoll = EpollContext::new().unwrap();
|
|
epoll.add_event(&exit_evt, EpollDispatch::Exit).unwrap();
|
|
epoll.add_event(&api_evt, EpollDispatch::Api).unwrap();
|
|
|
|
let epoll_fd = epoll.as_raw_fd();
|
|
let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); 2];
|
|
let num_events;
|
|
loop {
|
|
num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) {
|
|
Ok(num_events) => num_events,
|
|
Err(e) => match e.raw_os_error() {
|
|
Some(libc::EAGAIN) | Some(libc::EINTR) => continue,
|
|
_ => panic!("Unexpected epoll::wait error!"),
|
|
},
|
|
};
|
|
|
|
break;
|
|
}
|
|
|
|
for event in events.iter().take(num_events) {
|
|
let dispatch_event: EpollDispatch = event.data.into();
|
|
match dispatch_event {
|
|
EpollDispatch::Exit => {
|
|
break;
|
|
}
|
|
EpollDispatch::Api => {
|
|
for _ in 0..api_evt.read().unwrap() {
|
|
let api_request = api_receiver.recv().unwrap();
|
|
api_request(&mut StubApiRequestHandler).unwrap();
|
|
}
|
|
}
|
|
_ => {
|
|
panic!("Unexpected Epoll event");
|
|
}
|
|
}
|
|
}
|
|
}
|