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