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 devices: None, 177 user_devices: None, 178 vdpa: None, 179 vsock: None, 180 pvpanic: false, 181 iommu: false, 182 #[cfg(target_arch = "x86_64")] 183 sgx_epc: None, 184 numa: None, 185 watchdog: false, 186 #[cfg(feature = "guest_debug")] 187 gdb: false, 188 platform: None, 189 tpm: None, 190 preserved_fds: None, 191 })), 192 state: VmState::Running, 193 memory_actual_size: 0, 194 device_tree: None, 195 }) 196 } 197 198 fn vmm_ping(&self) -> VmmPingResponse { 199 VmmPingResponse { 200 build_version: String::new(), 201 version: String::new(), 202 pid: 0, 203 features: Vec::new(), 204 } 205 } 206 207 fn vm_delete(&mut self) -> Result<(), VmError> { 208 Ok(()) 209 } 210 211 fn vmm_shutdown(&mut self) -> Result<(), VmError> { 212 Ok(()) 213 } 214 215 fn vm_resize(&mut self, _: Option<u8>, _: Option<u64>, _: Option<u64>) -> Result<(), VmError> { 216 Ok(()) 217 } 218 219 fn vm_resize_zone(&mut self, _: String, _: u64) -> Result<(), VmError> { 220 Ok(()) 221 } 222 223 fn vm_add_device(&mut self, _: DeviceConfig) -> Result<Option<Vec<u8>>, VmError> { 224 Ok(None) 225 } 226 227 fn vm_add_user_device(&mut self, _: UserDeviceConfig) -> Result<Option<Vec<u8>>, VmError> { 228 Ok(None) 229 } 230 231 fn vm_remove_device(&mut self, _: String) -> Result<(), VmError> { 232 Ok(()) 233 } 234 235 fn vm_add_disk(&mut self, _: DiskConfig) -> Result<Option<Vec<u8>>, VmError> { 236 Ok(None) 237 } 238 239 fn vm_add_fs(&mut self, _: FsConfig) -> Result<Option<Vec<u8>>, VmError> { 240 Ok(None) 241 } 242 243 fn vm_add_pmem(&mut self, _: PmemConfig) -> Result<Option<Vec<u8>>, VmError> { 244 Ok(None) 245 } 246 247 fn vm_add_net(&mut self, _: NetConfig) -> Result<Option<Vec<u8>>, VmError> { 248 Ok(None) 249 } 250 251 fn vm_add_vdpa(&mut self, _: VdpaConfig) -> Result<Option<Vec<u8>>, VmError> { 252 Ok(None) 253 } 254 255 fn vm_add_vsock(&mut self, _: VsockConfig) -> Result<Option<Vec<u8>>, VmError> { 256 Ok(None) 257 } 258 259 fn vm_counters(&mut self) -> Result<Option<Vec<u8>>, VmError> { 260 Ok(None) 261 } 262 263 fn vm_power_button(&mut self) -> Result<(), VmError> { 264 Ok(()) 265 } 266 267 fn vm_receive_migration(&mut self, _: VmReceiveMigrationData) -> Result<(), MigratableError> { 268 Ok(()) 269 } 270 271 fn vm_send_migration(&mut self, _: VmSendMigrationData) -> Result<(), MigratableError> { 272 Ok(()) 273 } 274 } 275 276 fn http_receiver_stub(exit_evt: EventFd, api_evt: EventFd, api_receiver: Receiver<ApiRequest>) { 277 let mut epoll = EpollContext::new().unwrap(); 278 epoll.add_event(&exit_evt, EpollDispatch::Exit).unwrap(); 279 epoll.add_event(&api_evt, EpollDispatch::Api).unwrap(); 280 281 let epoll_fd = epoll.as_raw_fd(); 282 let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); 2]; 283 let num_events; 284 loop { 285 num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) { 286 Ok(num_events) => num_events, 287 Err(e) => match e.raw_os_error() { 288 Some(libc::EAGAIN) | Some(libc::EINTR) => continue, 289 _ => panic!("Unexpected epoll::wait error!"), 290 }, 291 }; 292 293 break; 294 } 295 296 for event in events.iter().take(num_events) { 297 let dispatch_event: EpollDispatch = event.data.into(); 298 match dispatch_event { 299 EpollDispatch::Exit => { 300 break; 301 } 302 EpollDispatch::Api => { 303 for _ in 0..api_evt.read().unwrap() { 304 let api_request = api_receiver.recv().unwrap(); 305 api_request(&mut StubApiRequestHandler).unwrap(); 306 } 307 } 308 _ => { 309 panic!("Unexpected Epoll event"); 310 } 311 } 312 } 313 } 314