1 // Copyright © 2022 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 #![no_main] 6 use std::os::unix::io::AsRawFd; 7 use std::path::PathBuf; 8 use std::sync::mpsc::{channel, Receiver}; 9 use std::thread; 10 11 use libfuzzer_sys::{fuzz_target, Corpus}; 12 use micro_http::Request; 13 use once_cell::sync::Lazy; 14 use vm_migration::MigratableError; 15 use vmm::api::http::*; 16 use vmm::api::{ 17 ApiRequest, RequestHandler, VmInfoResponse, VmReceiveMigrationData, VmSendMigrationData, 18 VmmPingResponse, 19 }; 20 use vmm::config::RestoreConfig; 21 use vmm::vm::{Error as VmError, VmState}; 22 use vmm::vm_config::*; 23 use vmm::{EpollContext, EpollDispatch}; 24 use vmm_sys_util::eventfd::EventFd; 25 26 // Need to be ordered for test case reproducibility 27 static ROUTES: Lazy<Vec<&Box<dyn EndpointHandler + Sync + Send>>> = 28 Lazy::new(|| HTTP_ROUTES.routes.values().collect()); 29 30 fuzz_target!(|bytes: &[u8]| -> Corpus { 31 if bytes.len() < 2 { 32 return Corpus::Reject; 33 } 34 35 let route = ROUTES[bytes[0] as usize % ROUTES.len()]; 36 if let Some(request) = generate_request(&bytes[1..]) { 37 let exit_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap(); 38 let api_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap(); 39 let (api_sender, api_receiver) = channel(); 40 41 let http_receiver_thread = { 42 let exit_evt = exit_evt.try_clone().unwrap(); 43 let api_evt = api_evt.try_clone().unwrap(); 44 thread::Builder::new() 45 .name("http_receiver".to_string()) 46 .spawn(move || { 47 http_receiver_stub(exit_evt, api_evt, api_receiver); 48 }) 49 .unwrap() 50 }; 51 52 route.handle_request(&request, api_evt, api_sender); 53 exit_evt.write(1).ok(); 54 http_receiver_thread.join().unwrap(); 55 }; 56 57 Corpus::Keep 58 }); 59 60 fn generate_request(bytes: &[u8]) -> Option<Request> { 61 let req_method = match bytes[0] % 5 { 62 0 => "GET", 63 1 => "PUT", 64 2 => "PATCH", 65 3 => "POST", 66 _ => "INVALID", 67 }; 68 let request_line = format!("{} http://localhost/home HTTP/1.1\r\n", req_method); 69 70 let req_body = &bytes[1..]; 71 let request = if req_body.len() > 0 { 72 [ 73 format!("{}Content-Length: {}\r\n", request_line, req_body.len()).as_bytes(), 74 req_body, 75 ] 76 .concat() 77 } else { 78 format!("{}\r\n", request_line).as_bytes().to_vec() 79 }; 80 81 Request::try_from(&request, None).ok() 82 } 83 84 struct StubApiRequestHandler; 85 86 impl RequestHandler for StubApiRequestHandler { 87 fn vm_create(&mut self, _: Box<VmConfig>) -> Result<(), VmError> { 88 Ok(()) 89 } 90 91 fn vm_boot(&mut self) -> Result<(), VmError> { 92 Ok(()) 93 } 94 95 fn vm_pause(&mut self) -> Result<(), VmError> { 96 Ok(()) 97 } 98 99 fn vm_resume(&mut self) -> Result<(), VmError> { 100 Ok(()) 101 } 102 103 fn vm_snapshot(&mut self, _: &str) -> Result<(), VmError> { 104 Ok(()) 105 } 106 107 fn vm_restore(&mut self, _: RestoreConfig) -> Result<(), VmError> { 108 Ok(()) 109 } 110 111 #[cfg(target_arch = "x86_64")] 112 fn vm_coredump(&mut self, _: &str) -> Result<(), VmError> { 113 Ok(()) 114 } 115 116 fn vm_shutdown(&mut self) -> Result<(), VmError> { 117 Ok(()) 118 } 119 120 fn vm_reboot(&mut self) -> Result<(), VmError> { 121 Ok(()) 122 } 123 124 fn vm_info(&self) -> Result<VmInfoResponse, VmError> { 125 Ok(VmInfoResponse { 126 config: Box::new(VmConfig { 127 cpus: CpusConfig { 128 boot_vcpus: 1, 129 max_vcpus: 1, 130 topology: None, 131 kvm_hyperv: false, 132 max_phys_bits: 46, 133 affinity: None, 134 features: CpuFeatures::default(), 135 }, 136 memory: MemoryConfig { 137 size: 536_870_912, 138 mergeable: false, 139 hotplug_method: HotplugMethod::Acpi, 140 hotplug_size: None, 141 hotplugged_size: None, 142 shared: false, 143 hugepages: false, 144 hugepage_size: None, 145 prefault: false, 146 zones: None, 147 thp: true, 148 }, 149 payload: Some(PayloadConfig { 150 kernel: Some(PathBuf::from("/path/to/kernel")), 151 firmware: None, 152 cmdline: None, 153 initramfs: None, 154 #[cfg(feature = "igvm")] 155 igvm: None, 156 }), 157 rate_limit_groups: None, 158 disks: None, 159 net: None, 160 rng: RngConfig { 161 src: PathBuf::from("/dev/urandom"), 162 iommu: false, 163 }, 164 balloon: None, 165 fs: None, 166 pmem: None, 167 serial: ConsoleConfig { 168 file: None, 169 mode: ConsoleOutputMode::Null, 170 iommu: false, 171 socket: None, 172 }, 173 console: ConsoleConfig { 174 file: None, 175 mode: ConsoleOutputMode::Tty, 176 iommu: false, 177 socket: None, 178 }, 179 #[cfg(target_arch = "x86_64")] 180 debug_console: DebugConsoleConfig::default(), 181 devices: None, 182 user_devices: None, 183 vdpa: None, 184 vsock: None, 185 pvpanic: false, 186 #[cfg(feature = "pvmemcontrol")] 187 pvmemcontrol: None, 188 iommu: false, 189 #[cfg(target_arch = "x86_64")] 190 sgx_epc: None, 191 numa: None, 192 watchdog: false, 193 gdb: false, 194 pci_segments: None, 195 platform: None, 196 tpm: None, 197 preserved_fds: None, 198 landlock_enable: false, 199 landlock_rules: None, 200 }), 201 state: VmState::Running, 202 memory_actual_size: 0, 203 device_tree: None, 204 }) 205 } 206 207 fn vmm_ping(&self) -> VmmPingResponse { 208 VmmPingResponse { 209 build_version: String::new(), 210 version: String::new(), 211 pid: 0, 212 features: Vec::new(), 213 } 214 } 215 216 fn vm_delete(&mut self) -> Result<(), VmError> { 217 Ok(()) 218 } 219 220 fn vmm_shutdown(&mut self) -> Result<(), VmError> { 221 Ok(()) 222 } 223 224 fn vm_resize(&mut self, _: Option<u8>, _: Option<u64>, _: Option<u64>) -> Result<(), VmError> { 225 Ok(()) 226 } 227 228 fn vm_resize_zone(&mut self, _: String, _: u64) -> Result<(), VmError> { 229 Ok(()) 230 } 231 232 fn vm_add_device(&mut self, _: DeviceConfig) -> Result<Option<Vec<u8>>, VmError> { 233 Ok(None) 234 } 235 236 fn vm_add_user_device(&mut self, _: UserDeviceConfig) -> Result<Option<Vec<u8>>, VmError> { 237 Ok(None) 238 } 239 240 fn vm_remove_device(&mut self, _: String) -> Result<(), VmError> { 241 Ok(()) 242 } 243 244 fn vm_add_disk(&mut self, _: DiskConfig) -> Result<Option<Vec<u8>>, VmError> { 245 Ok(None) 246 } 247 248 fn vm_add_fs(&mut self, _: FsConfig) -> Result<Option<Vec<u8>>, VmError> { 249 Ok(None) 250 } 251 252 fn vm_add_pmem(&mut self, _: PmemConfig) -> Result<Option<Vec<u8>>, VmError> { 253 Ok(None) 254 } 255 256 fn vm_add_net(&mut self, _: NetConfig) -> Result<Option<Vec<u8>>, VmError> { 257 Ok(None) 258 } 259 260 fn vm_add_vdpa(&mut self, _: VdpaConfig) -> Result<Option<Vec<u8>>, VmError> { 261 Ok(None) 262 } 263 264 fn vm_add_vsock(&mut self, _: VsockConfig) -> Result<Option<Vec<u8>>, VmError> { 265 Ok(None) 266 } 267 268 fn vm_counters(&mut self) -> Result<Option<Vec<u8>>, VmError> { 269 Ok(None) 270 } 271 272 fn vm_power_button(&mut self) -> Result<(), VmError> { 273 Ok(()) 274 } 275 276 fn vm_receive_migration(&mut self, _: VmReceiveMigrationData) -> Result<(), MigratableError> { 277 Ok(()) 278 } 279 280 fn vm_send_migration(&mut self, _: VmSendMigrationData) -> Result<(), MigratableError> { 281 Ok(()) 282 } 283 284 fn vm_nmi(&mut self) -> Result<(), VmError> { 285 Ok(()) 286 } 287 } 288 289 fn http_receiver_stub(exit_evt: EventFd, api_evt: EventFd, api_receiver: Receiver<ApiRequest>) { 290 let mut epoll = EpollContext::new().unwrap(); 291 epoll.add_event(&exit_evt, EpollDispatch::Exit).unwrap(); 292 epoll.add_event(&api_evt, EpollDispatch::Api).unwrap(); 293 294 let epoll_fd = epoll.as_raw_fd(); 295 let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); 2]; 296 let num_events; 297 loop { 298 num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) { 299 Ok(num_events) => num_events, 300 Err(e) => match e.raw_os_error() { 301 Some(libc::EAGAIN) | Some(libc::EINTR) => continue, 302 _ => panic!("Unexpected epoll::wait error!"), 303 }, 304 }; 305 306 break; 307 } 308 309 for event in events.iter().take(num_events) { 310 let dispatch_event: EpollDispatch = event.data.into(); 311 match dispatch_event { 312 EpollDispatch::Exit => { 313 break; 314 } 315 EpollDispatch::Api => { 316 for _ in 0..api_evt.read().unwrap() { 317 let api_request = api_receiver.recv().unwrap(); 318 api_request(&mut StubApiRequestHandler).unwrap(); 319 } 320 } 321 _ => { 322 panic!("Unexpected Epoll event"); 323 } 324 } 325 } 326 } 327