xref: /cloud-hypervisor/fuzz/fuzz_targets/http_api.rs (revision eea9bcea38e0c5649f444c829f3a4f9c22aa486c)
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::sync::mpsc::{channel, Receiver};
11 use std::thread;
12 use vmm::api::{http::*, ApiRequest, ApiResponsePayload};
13 use vmm::{EpollContext, EpollDispatch};
14 use vmm_sys_util::eventfd::EventFd;
15 
16 // Need to be ordered for test case reproducibility
17 static ROUTES: Lazy<Vec<&Box<dyn EndpointHandler + Sync + Send>>> =
18     Lazy::new(|| HTTP_ROUTES.routes.values().collect());
19 
20 fuzz_target!(|bytes| {
21     if bytes.len() < 2 {
22         return;
23     }
24 
25     let route = ROUTES[bytes[0] as usize % ROUTES.len()];
26     if let Some(request) = generate_request(&bytes[1..]) {
27         let exit_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
28         let api_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
29         let (api_sender, api_receiver) = channel();
30 
31         let http_receiver_thread = {
32             let exit_evt = exit_evt.try_clone().unwrap();
33             let api_evt = api_evt.try_clone().unwrap();
34             thread::Builder::new()
35                 .name("http_receiver".to_string())
36                 .spawn(move || {
37                     http_receiver_stub(exit_evt, api_evt, api_receiver);
38                 })
39                 .unwrap()
40         };
41 
42         route.handle_request(&request, api_evt, api_sender);
43         exit_evt.write(1).ok();
44         http_receiver_thread.join().unwrap();
45     };
46 });
47 
48 fn generate_request(bytes: &[u8]) -> Option<Request> {
49     let req_method = match bytes[0] % 5 {
50         0 => "GET",
51         1 => "PUT",
52         2 => "PATCH",
53         3 => "POST",
54         _ => "INVALID",
55     };
56     let request_line = format!("{} http://localhost/home HTTP/1.1\r\n", req_method);
57 
58     let req_body = &bytes[1..];
59     let request = if req_body.len() > 0 {
60         [
61             format!("{}Content-Length: {}\r\n", request_line, req_body.len()).as_bytes(),
62             req_body,
63         ]
64         .concat()
65     } else {
66         format!("{}\r\n", request_line).as_bytes().to_vec()
67     };
68 
69     Request::try_from(&request, None).ok()
70 }
71 
72 fn http_receiver_stub(exit_evt: EventFd, api_evt: EventFd, api_receiver: Receiver<ApiRequest>) {
73     let mut epoll = EpollContext::new().unwrap();
74     epoll.add_event(&exit_evt, EpollDispatch::Exit).unwrap();
75     epoll.add_event(&api_evt, EpollDispatch::Api).unwrap();
76 
77     let epoll_fd = epoll.as_raw_fd();
78     let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); 2];
79     let num_events;
80     loop {
81         num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) {
82             Ok(num_events) => num_events,
83             Err(e) => match e.raw_os_error() {
84                 Some(libc::EAGAIN) | Some(libc::EINTR) => continue,
85                 _ => panic!("Unexpected epoll::wait error!"),
86             },
87         };
88 
89         break;
90     }
91 
92     for event in events.iter().take(num_events) {
93         let dispatch_event: EpollDispatch = event.data.into();
94         match dispatch_event {
95             EpollDispatch::Exit => {
96                 break;
97             }
98             EpollDispatch::Api => {
99                 for _ in 0..api_evt.read().unwrap() {
100                     let api_request = api_receiver.recv().unwrap();
101                     match api_request {
102                         ApiRequest::VmCreate(_, sender) => {
103                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
104                         }
105                         ApiRequest::VmDelete(sender) => {
106                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
107                         }
108                         ApiRequest::VmBoot(sender) => {
109                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
110                         }
111                         ApiRequest::VmShutdown(sender) => {
112                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
113                         }
114                         ApiRequest::VmReboot(sender) => {
115                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
116                         }
117                         ApiRequest::VmInfo(sender) => {
118                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
119                         }
120                         ApiRequest::VmmPing(sender) => {
121                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
122                         }
123                         ApiRequest::VmPause(sender) => {
124                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
125                         }
126                         ApiRequest::VmResume(sender) => {
127                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
128                         }
129                         ApiRequest::VmSnapshot(_, sender) => {
130                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
131                         }
132                         ApiRequest::VmRestore(_, sender) => {
133                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
134                         }
135                         ApiRequest::VmmShutdown(sender) => {
136                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
137                         }
138                         ApiRequest::VmResize(_, sender) => {
139                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
140                         }
141                         ApiRequest::VmResizeZone(_, sender) => {
142                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
143                         }
144                         ApiRequest::VmAddDevice(_, sender) => {
145                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
146                         }
147                         ApiRequest::VmAddUserDevice(_, sender) => {
148                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
149                         }
150                         ApiRequest::VmRemoveDevice(_, sender) => {
151                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
152                         }
153                         ApiRequest::VmAddDisk(_, sender) => {
154                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
155                         }
156                         ApiRequest::VmAddFs(_, sender) => {
157                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
158                         }
159                         ApiRequest::VmAddPmem(_, sender) => {
160                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
161                         }
162                         ApiRequest::VmAddNet(_, sender) => {
163                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
164                         }
165                         ApiRequest::VmAddVdpa(_, sender) => {
166                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
167                         }
168                         ApiRequest::VmAddVsock(_, sender) => {
169                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
170                         }
171                         ApiRequest::VmCounters(sender) => {
172                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
173                         }
174                         ApiRequest::VmReceiveMigration(_, sender) => {
175                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
176                         }
177                         ApiRequest::VmSendMigration(_, sender) => {
178                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
179                         }
180                         ApiRequest::VmPowerButton(sender) => {
181                             sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
182                         }
183                     }
184                 }
185             }
186             _ => {
187                 panic!("Unexpected Epoll event");
188             }
189         }
190     }
191 }
192