xref: /cloud-hypervisor/fuzz/fuzz_targets/http_api.rs (revision 4182ef91e03131731a10b1af2b36c36af476a521)
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