1e5155babSBo Chen // Copyright © 2022 Intel Corporation
2e5155babSBo Chen //
3e5155babSBo Chen // SPDX-License-Identifier: Apache-2.0
4e5155babSBo Chen
5e5155babSBo Chen #![no_main]
6e5155babSBo Chen use std::os::unix::io::AsRawFd;
74ca18c08SAlyssa Ross use std::path::PathBuf;
8e5155babSBo Chen use std::sync::mpsc::{channel, Receiver};
9*4182ef91SPhilipp Schuster use std::sync::LazyLock;
10e5155babSBo Chen use std::thread;
11f041c940SRob Bradford
126fd5b0f6SWei Liu use libfuzzer_sys::{fuzz_target, Corpus};
13f041c940SRob Bradford use micro_http::Request;
144ca18c08SAlyssa Ross use vm_migration::MigratableError;
1561e57e1cSRuoqing He use vmm::api::http::*;
164ca18c08SAlyssa Ross use vmm::api::{
1761e57e1cSRuoqing He ApiRequest, RequestHandler, VmInfoResponse, VmReceiveMigrationData, VmSendMigrationData,
1861e57e1cSRuoqing He VmmPingResponse,
194ca18c08SAlyssa Ross };
204ca18c08SAlyssa Ross use vmm::config::RestoreConfig;
214ca18c08SAlyssa Ross use vmm::vm::{Error as VmError, VmState};
224ca18c08SAlyssa Ross use vmm::vm_config::*;
23e5155babSBo Chen use vmm::{EpollContext, EpollDispatch};
24e5155babSBo Chen use vmm_sys_util::eventfd::EventFd;
25e5155babSBo Chen
26e5155babSBo Chen // Need to be ordered for test case reproducibility
27*4182ef91SPhilipp Schuster static ROUTES: LazyLock<Vec<&Box<dyn EndpointHandler + Sync + Send>>> =
28*4182ef91SPhilipp Schuster LazyLock::new(|| HTTP_ROUTES.routes.values().collect());
29e5155babSBo Chen
306fd5b0f6SWei Liu fuzz_target!(|bytes: &[u8]| -> Corpus {
31e5155babSBo Chen if bytes.len() < 2 {
326fd5b0f6SWei Liu return Corpus::Reject;
33e5155babSBo Chen }
34e5155babSBo Chen
35e5155babSBo Chen let route = ROUTES[bytes[0] as usize % ROUTES.len()];
36e5155babSBo Chen if let Some(request) = generate_request(&bytes[1..]) {
37e5155babSBo Chen let exit_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
38e5155babSBo Chen let api_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
39e5155babSBo Chen let (api_sender, api_receiver) = channel();
40e5155babSBo Chen
41e5155babSBo Chen let http_receiver_thread = {
42e5155babSBo Chen let exit_evt = exit_evt.try_clone().unwrap();
43e5155babSBo Chen let api_evt = api_evt.try_clone().unwrap();
44e5155babSBo Chen thread::Builder::new()
45e5155babSBo Chen .name("http_receiver".to_string())
46e5155babSBo Chen .spawn(move || {
47e5155babSBo Chen http_receiver_stub(exit_evt, api_evt, api_receiver);
48e5155babSBo Chen })
49e5155babSBo Chen .unwrap()
50e5155babSBo Chen };
51e5155babSBo Chen
52e5155babSBo Chen route.handle_request(&request, api_evt, api_sender);
53e5155babSBo Chen exit_evt.write(1).ok();
54e5155babSBo Chen http_receiver_thread.join().unwrap();
55e5155babSBo Chen };
566fd5b0f6SWei Liu
576fd5b0f6SWei Liu Corpus::Keep
58e5155babSBo Chen });
59e5155babSBo Chen
generate_request(bytes: &[u8]) -> Option<Request>60e5155babSBo Chen fn generate_request(bytes: &[u8]) -> Option<Request> {
61e5155babSBo Chen let req_method = match bytes[0] % 5 {
62e5155babSBo Chen 0 => "GET",
63e5155babSBo Chen 1 => "PUT",
64e5155babSBo Chen 2 => "PATCH",
65e5155babSBo Chen 3 => "POST",
66e5155babSBo Chen _ => "INVALID",
67e5155babSBo Chen };
68e5155babSBo Chen let request_line = format!("{} http://localhost/home HTTP/1.1\r\n", req_method);
69e5155babSBo Chen
70e5155babSBo Chen let req_body = &bytes[1..];
71e5155babSBo Chen let request = if req_body.len() > 0 {
72e5155babSBo Chen [
73e5155babSBo Chen format!("{}Content-Length: {}\r\n", request_line, req_body.len()).as_bytes(),
74e5155babSBo Chen req_body,
75e5155babSBo Chen ]
76e5155babSBo Chen .concat()
77e5155babSBo Chen } else {
78e5155babSBo Chen format!("{}\r\n", request_line).as_bytes().to_vec()
79e5155babSBo Chen };
80e5155babSBo Chen
81e5155babSBo Chen Request::try_from(&request, None).ok()
82e5155babSBo Chen }
83e5155babSBo Chen
844ca18c08SAlyssa Ross struct StubApiRequestHandler;
854ca18c08SAlyssa Ross
864ca18c08SAlyssa Ross impl RequestHandler for StubApiRequestHandler {
vm_create(&mut self, _: Box<VmConfig>) -> Result<(), VmError>87cc9899e0SSongqian Li fn vm_create(&mut self, _: Box<VmConfig>) -> Result<(), VmError> {
884ca18c08SAlyssa Ross Ok(())
894ca18c08SAlyssa Ross }
904ca18c08SAlyssa Ross
vm_boot(&mut self) -> Result<(), VmError>914ca18c08SAlyssa Ross fn vm_boot(&mut self) -> Result<(), VmError> {
924ca18c08SAlyssa Ross Ok(())
934ca18c08SAlyssa Ross }
944ca18c08SAlyssa Ross
vm_pause(&mut self) -> Result<(), VmError>954ca18c08SAlyssa Ross fn vm_pause(&mut self) -> Result<(), VmError> {
964ca18c08SAlyssa Ross Ok(())
974ca18c08SAlyssa Ross }
984ca18c08SAlyssa Ross
vm_resume(&mut self) -> Result<(), VmError>994ca18c08SAlyssa Ross fn vm_resume(&mut self) -> Result<(), VmError> {
1004ca18c08SAlyssa Ross Ok(())
1014ca18c08SAlyssa Ross }
1024ca18c08SAlyssa Ross
vm_snapshot(&mut self, _: &str) -> Result<(), VmError>1034ca18c08SAlyssa Ross fn vm_snapshot(&mut self, _: &str) -> Result<(), VmError> {
1044ca18c08SAlyssa Ross Ok(())
1054ca18c08SAlyssa Ross }
1064ca18c08SAlyssa Ross
vm_restore(&mut self, _: RestoreConfig) -> Result<(), VmError>1074ca18c08SAlyssa Ross fn vm_restore(&mut self, _: RestoreConfig) -> Result<(), VmError> {
1084ca18c08SAlyssa Ross Ok(())
1094ca18c08SAlyssa Ross }
1104ca18c08SAlyssa Ross
1113def18f5SRob Bradford #[cfg(target_arch = "x86_64")]
vm_coredump(&mut self, _: &str) -> Result<(), VmError>1124ca18c08SAlyssa Ross fn vm_coredump(&mut self, _: &str) -> Result<(), VmError> {
1134ca18c08SAlyssa Ross Ok(())
1144ca18c08SAlyssa Ross }
1154ca18c08SAlyssa Ross
vm_shutdown(&mut self) -> Result<(), VmError>1164ca18c08SAlyssa Ross fn vm_shutdown(&mut self) -> Result<(), VmError> {
1174ca18c08SAlyssa Ross Ok(())
1184ca18c08SAlyssa Ross }
1194ca18c08SAlyssa Ross
vm_reboot(&mut self) -> Result<(), VmError>1204ca18c08SAlyssa Ross fn vm_reboot(&mut self) -> Result<(), VmError> {
1214ca18c08SAlyssa Ross Ok(())
1224ca18c08SAlyssa Ross }
1234ca18c08SAlyssa Ross
vm_info(&self) -> Result<VmInfoResponse, VmError>1244ca18c08SAlyssa Ross fn vm_info(&self) -> Result<VmInfoResponse, VmError> {
1254ca18c08SAlyssa Ross Ok(VmInfoResponse {
126cc9899e0SSongqian Li config: Box::new(VmConfig {
1274ca18c08SAlyssa Ross cpus: CpusConfig {
1284ca18c08SAlyssa Ross boot_vcpus: 1,
1294ca18c08SAlyssa Ross max_vcpus: 1,
1304ca18c08SAlyssa Ross topology: None,
1314ca18c08SAlyssa Ross kvm_hyperv: false,
1324ca18c08SAlyssa Ross max_phys_bits: 46,
1334ca18c08SAlyssa Ross affinity: None,
1344ca18c08SAlyssa Ross features: CpuFeatures::default(),
1354ca18c08SAlyssa Ross },
1364ca18c08SAlyssa Ross memory: MemoryConfig {
1374ca18c08SAlyssa Ross size: 536_870_912,
1384ca18c08SAlyssa Ross mergeable: false,
1394ca18c08SAlyssa Ross hotplug_method: HotplugMethod::Acpi,
1404ca18c08SAlyssa Ross hotplug_size: None,
1414ca18c08SAlyssa Ross hotplugged_size: None,
1424ca18c08SAlyssa Ross shared: false,
1434ca18c08SAlyssa Ross hugepages: false,
1444ca18c08SAlyssa Ross hugepage_size: None,
1454ca18c08SAlyssa Ross prefault: false,
1464ca18c08SAlyssa Ross zones: None,
1474ca18c08SAlyssa Ross thp: true,
1484ca18c08SAlyssa Ross },
1494ca18c08SAlyssa Ross payload: Some(PayloadConfig {
1504ca18c08SAlyssa Ross kernel: Some(PathBuf::from("/path/to/kernel")),
15176741961SAlyssa Ross firmware: None,
15276741961SAlyssa Ross cmdline: None,
15376741961SAlyssa Ross initramfs: None,
15476741961SAlyssa Ross #[cfg(feature = "igvm")]
15576741961SAlyssa Ross igvm: None,
1564ca18c08SAlyssa Ross }),
1574ca18c08SAlyssa Ross rate_limit_groups: None,
1584ca18c08SAlyssa Ross disks: None,
1594ca18c08SAlyssa Ross net: None,
1604ca18c08SAlyssa Ross rng: RngConfig {
1614ca18c08SAlyssa Ross src: PathBuf::from("/dev/urandom"),
1624ca18c08SAlyssa Ross iommu: false,
1634ca18c08SAlyssa Ross },
1644ca18c08SAlyssa Ross balloon: None,
1654ca18c08SAlyssa Ross fs: None,
1664ca18c08SAlyssa Ross pmem: None,
1674ca18c08SAlyssa Ross serial: ConsoleConfig {
1684ca18c08SAlyssa Ross file: None,
1694ca18c08SAlyssa Ross mode: ConsoleOutputMode::Null,
1704ca18c08SAlyssa Ross iommu: false,
1714ca18c08SAlyssa Ross socket: None,
1724ca18c08SAlyssa Ross },
1734ca18c08SAlyssa Ross console: ConsoleConfig {
1744ca18c08SAlyssa Ross file: None,
1754ca18c08SAlyssa Ross mode: ConsoleOutputMode::Tty,
1764ca18c08SAlyssa Ross iommu: false,
1774ca18c08SAlyssa Ross socket: None,
1784ca18c08SAlyssa Ross },
179e50a6411SPhilipp Schuster #[cfg(target_arch = "x86_64")]
180e50a6411SPhilipp Schuster debug_console: DebugConsoleConfig::default(),
1814ca18c08SAlyssa Ross devices: None,
1824ca18c08SAlyssa Ross user_devices: None,
1834ca18c08SAlyssa Ross vdpa: None,
1844ca18c08SAlyssa Ross vsock: None,
1854ca18c08SAlyssa Ross pvpanic: false,
1865f18ac3bSYuanchu Xie #[cfg(feature = "pvmemcontrol")]
1875f18ac3bSYuanchu Xie pvmemcontrol: None,
1884ca18c08SAlyssa Ross iommu: false,
1894ca18c08SAlyssa Ross #[cfg(target_arch = "x86_64")]
1904ca18c08SAlyssa Ross sgx_epc: None,
1914ca18c08SAlyssa Ross numa: None,
1924ca18c08SAlyssa Ross watchdog: false,
1934ca18c08SAlyssa Ross gdb: false,
194e7e856d8SThomas Barrett pci_segments: None,
1954ca18c08SAlyssa Ross platform: None,
1964ca18c08SAlyssa Ross tpm: None,
1974ca18c08SAlyssa Ross preserved_fds: None,
198d2f0e8aeSPraveen K Paladugu landlock_enable: false,
199bd180bc3SPraveen K Paladugu landlock_rules: None,
200cc9899e0SSongqian Li }),
2014ca18c08SAlyssa Ross state: VmState::Running,
2024ca18c08SAlyssa Ross memory_actual_size: 0,
2034ca18c08SAlyssa Ross device_tree: None,
2044ca18c08SAlyssa Ross })
2054ca18c08SAlyssa Ross }
2064ca18c08SAlyssa Ross
vmm_ping(&self) -> VmmPingResponse2074ca18c08SAlyssa Ross fn vmm_ping(&self) -> VmmPingResponse {
2084ca18c08SAlyssa Ross VmmPingResponse {
2094ca18c08SAlyssa Ross build_version: String::new(),
2104ca18c08SAlyssa Ross version: String::new(),
2114ca18c08SAlyssa Ross pid: 0,
2124ca18c08SAlyssa Ross features: Vec::new(),
2134ca18c08SAlyssa Ross }
2144ca18c08SAlyssa Ross }
2154ca18c08SAlyssa Ross
vm_delete(&mut self) -> Result<(), VmError>2164ca18c08SAlyssa Ross fn vm_delete(&mut self) -> Result<(), VmError> {
2174ca18c08SAlyssa Ross Ok(())
2184ca18c08SAlyssa Ross }
2194ca18c08SAlyssa Ross
vmm_shutdown(&mut self) -> Result<(), VmError>2204ca18c08SAlyssa Ross fn vmm_shutdown(&mut self) -> Result<(), VmError> {
2214ca18c08SAlyssa Ross Ok(())
2224ca18c08SAlyssa Ross }
2234ca18c08SAlyssa Ross
vm_resize(&mut self, _: Option<u8>, _: Option<u64>, _: Option<u64>) -> Result<(), VmError>2244ca18c08SAlyssa Ross fn vm_resize(&mut self, _: Option<u8>, _: Option<u64>, _: Option<u64>) -> Result<(), VmError> {
2254ca18c08SAlyssa Ross Ok(())
2264ca18c08SAlyssa Ross }
2274ca18c08SAlyssa Ross
vm_resize_zone(&mut self, _: String, _: u64) -> Result<(), VmError>2284ca18c08SAlyssa Ross fn vm_resize_zone(&mut self, _: String, _: u64) -> Result<(), VmError> {
2294ca18c08SAlyssa Ross Ok(())
2304ca18c08SAlyssa Ross }
2314ca18c08SAlyssa Ross
vm_add_device(&mut self, _: DeviceConfig) -> Result<Option<Vec<u8>>, VmError>2324ca18c08SAlyssa Ross fn vm_add_device(&mut self, _: DeviceConfig) -> Result<Option<Vec<u8>>, VmError> {
2334ca18c08SAlyssa Ross Ok(None)
2344ca18c08SAlyssa Ross }
2354ca18c08SAlyssa Ross
vm_add_user_device(&mut self, _: UserDeviceConfig) -> Result<Option<Vec<u8>>, VmError>2364ca18c08SAlyssa Ross fn vm_add_user_device(&mut self, _: UserDeviceConfig) -> Result<Option<Vec<u8>>, VmError> {
2374ca18c08SAlyssa Ross Ok(None)
2384ca18c08SAlyssa Ross }
2394ca18c08SAlyssa Ross
vm_remove_device(&mut self, _: String) -> Result<(), VmError>2404ca18c08SAlyssa Ross fn vm_remove_device(&mut self, _: String) -> Result<(), VmError> {
2414ca18c08SAlyssa Ross Ok(())
2424ca18c08SAlyssa Ross }
2434ca18c08SAlyssa Ross
vm_add_disk(&mut self, _: DiskConfig) -> Result<Option<Vec<u8>>, VmError>2444ca18c08SAlyssa Ross fn vm_add_disk(&mut self, _: DiskConfig) -> Result<Option<Vec<u8>>, VmError> {
2454ca18c08SAlyssa Ross Ok(None)
2464ca18c08SAlyssa Ross }
2474ca18c08SAlyssa Ross
vm_add_fs(&mut self, _: FsConfig) -> Result<Option<Vec<u8>>, VmError>2484ca18c08SAlyssa Ross fn vm_add_fs(&mut self, _: FsConfig) -> Result<Option<Vec<u8>>, VmError> {
2494ca18c08SAlyssa Ross Ok(None)
2504ca18c08SAlyssa Ross }
2514ca18c08SAlyssa Ross
vm_add_pmem(&mut self, _: PmemConfig) -> Result<Option<Vec<u8>>, VmError>2524ca18c08SAlyssa Ross fn vm_add_pmem(&mut self, _: PmemConfig) -> Result<Option<Vec<u8>>, VmError> {
2534ca18c08SAlyssa Ross Ok(None)
2544ca18c08SAlyssa Ross }
2554ca18c08SAlyssa Ross
vm_add_net(&mut self, _: NetConfig) -> Result<Option<Vec<u8>>, VmError>2564ca18c08SAlyssa Ross fn vm_add_net(&mut self, _: NetConfig) -> Result<Option<Vec<u8>>, VmError> {
2574ca18c08SAlyssa Ross Ok(None)
2584ca18c08SAlyssa Ross }
2594ca18c08SAlyssa Ross
vm_add_vdpa(&mut self, _: VdpaConfig) -> Result<Option<Vec<u8>>, VmError>2604ca18c08SAlyssa Ross fn vm_add_vdpa(&mut self, _: VdpaConfig) -> Result<Option<Vec<u8>>, VmError> {
2614ca18c08SAlyssa Ross Ok(None)
2624ca18c08SAlyssa Ross }
2634ca18c08SAlyssa Ross
vm_add_vsock(&mut self, _: VsockConfig) -> Result<Option<Vec<u8>>, VmError>2644ca18c08SAlyssa Ross fn vm_add_vsock(&mut self, _: VsockConfig) -> Result<Option<Vec<u8>>, VmError> {
2654ca18c08SAlyssa Ross Ok(None)
2664ca18c08SAlyssa Ross }
2674ca18c08SAlyssa Ross
vm_counters(&mut self) -> Result<Option<Vec<u8>>, VmError>2684ca18c08SAlyssa Ross fn vm_counters(&mut self) -> Result<Option<Vec<u8>>, VmError> {
2694ca18c08SAlyssa Ross Ok(None)
2704ca18c08SAlyssa Ross }
2714ca18c08SAlyssa Ross
vm_power_button(&mut self) -> Result<(), VmError>2724ca18c08SAlyssa Ross fn vm_power_button(&mut self) -> Result<(), VmError> {
2734ca18c08SAlyssa Ross Ok(())
2744ca18c08SAlyssa Ross }
2754ca18c08SAlyssa Ross
vm_receive_migration(&mut self, _: VmReceiveMigrationData) -> Result<(), MigratableError>2764ca18c08SAlyssa Ross fn vm_receive_migration(&mut self, _: VmReceiveMigrationData) -> Result<(), MigratableError> {
2774ca18c08SAlyssa Ross Ok(())
2784ca18c08SAlyssa Ross }
2794ca18c08SAlyssa Ross
vm_send_migration(&mut self, _: VmSendMigrationData) -> Result<(), MigratableError>2804ca18c08SAlyssa Ross fn vm_send_migration(&mut self, _: VmSendMigrationData) -> Result<(), MigratableError> {
2814ca18c08SAlyssa Ross Ok(())
2824ca18c08SAlyssa Ross }
283f40dd4a9SYi Wang
vm_nmi(&mut self) -> Result<(), VmError>284f40dd4a9SYi Wang fn vm_nmi(&mut self) -> Result<(), VmError> {
285f40dd4a9SYi Wang Ok(())
286f40dd4a9SYi Wang }
2874ca18c08SAlyssa Ross }
2884ca18c08SAlyssa Ross
http_receiver_stub(exit_evt: EventFd, api_evt: EventFd, api_receiver: Receiver<ApiRequest>)289e5155babSBo Chen fn http_receiver_stub(exit_evt: EventFd, api_evt: EventFd, api_receiver: Receiver<ApiRequest>) {
290e5155babSBo Chen let mut epoll = EpollContext::new().unwrap();
291e5155babSBo Chen epoll.add_event(&exit_evt, EpollDispatch::Exit).unwrap();
292e5155babSBo Chen epoll.add_event(&api_evt, EpollDispatch::Api).unwrap();
293e5155babSBo Chen
294e5155babSBo Chen let epoll_fd = epoll.as_raw_fd();
295e5155babSBo Chen let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); 2];
296e5155babSBo Chen let num_events;
297e5155babSBo Chen loop {
298e5155babSBo Chen num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) {
299e5155babSBo Chen Ok(num_events) => num_events,
300e5155babSBo Chen Err(e) => match e.raw_os_error() {
301e5155babSBo Chen Some(libc::EAGAIN) | Some(libc::EINTR) => continue,
302e5155babSBo Chen _ => panic!("Unexpected epoll::wait error!"),
303e5155babSBo Chen },
304e5155babSBo Chen };
305e5155babSBo Chen
306e5155babSBo Chen break;
307e5155babSBo Chen }
308e5155babSBo Chen
309e5155babSBo Chen for event in events.iter().take(num_events) {
310e5155babSBo Chen let dispatch_event: EpollDispatch = event.data.into();
311e5155babSBo Chen match dispatch_event {
312e5155babSBo Chen EpollDispatch::Exit => {
313e5155babSBo Chen break;
314e5155babSBo Chen }
315e5155babSBo Chen EpollDispatch::Api => {
316e5155babSBo Chen for _ in 0..api_evt.read().unwrap() {
317e5155babSBo Chen let api_request = api_receiver.recv().unwrap();
3184ca18c08SAlyssa Ross api_request(&mut StubApiRequestHandler).unwrap();
319e5155babSBo Chen }
320e5155babSBo Chen }
321e5155babSBo Chen _ => {
322e5155babSBo Chen panic!("Unexpected Epoll event");
323e5155babSBo Chen }
324e5155babSBo Chen }
325e5155babSBo Chen }
326e5155babSBo Chen }
327