1use crate::diagnostics::send_log_entry;
6use crate::options::add_defaults;
7use crate::test::Test;
8use anyhow::{anyhow, Context as _, Result};
9use fidl_fuchsia_fuzzer::{
10 self as fuzz, Artifact as FidlArtifact, Input as FidlInput, Result_ as FuzzResult,
11};
12use fuchsia_fuzzctl::InputPair;
13use futures::{join, AsyncReadExt, AsyncWriteExt, StreamExt};
14use std::cell::RefCell;
15use std::rc::Rc;
16use {fuchsia_async as fasync, zx_status as zx};
17
18#[derive(Debug)]
24pub struct FakeController {
25 corpus_type: Rc<RefCell<fuzz::Corpus>>,
26 input_to_send: Rc<RefCell<Option<Vec<u8>>>>,
27 options: Rc<RefCell<fuzz::Options>>,
28 received_input: Rc<RefCell<Vec<u8>>>,
29 result: Rc<RefCell<Result<FuzzResult, zx::Status>>>,
30 status: Rc<RefCell<fuzz::Status>>,
31 stdout: Rc<RefCell<Option<fasync::Socket>>>,
32 stderr: Rc<RefCell<Option<fasync::Socket>>>,
33 syslog: Rc<RefCell<Option<fasync::Socket>>>,
34 canceled: Rc<RefCell<bool>>,
35}
36
37impl FakeController {
38 pub fn new() -> Self {
40 let status = fuzz::Status { running: Some(false), ..Default::default() };
41 let mut options = fuzz::Options::default();
42 add_defaults(&mut options);
43 Self {
44 corpus_type: Rc::new(RefCell::new(fuzz::Corpus::Seed)),
45 input_to_send: Rc::new(RefCell::new(None)),
46 options: Rc::new(RefCell::new(options)),
47 received_input: Rc::new(RefCell::new(Vec::new())),
48 result: Rc::new(RefCell::new(Ok(FuzzResult::NoErrors))),
49 status: Rc::new(RefCell::new(status)),
50 stdout: Rc::new(RefCell::new(None)),
51 stderr: Rc::new(RefCell::new(None)),
52 syslog: Rc::new(RefCell::new(None)),
53 canceled: Rc::new(RefCell::new(false)),
54 }
55 }
56
57 pub fn set_output(&self, output: fuzz::TestOutput, socket: fidl::Socket) -> zx::Status {
59 let socket = fasync::Socket::from_socket(socket);
60 match output {
61 fuzz::TestOutput::Stdout => {
62 let mut stdout_mut = self.stdout.borrow_mut();
63 *stdout_mut = Some(socket);
64 }
65 fuzz::TestOutput::Stderr => {
66 let mut stderr_mut = self.stderr.borrow_mut();
67 *stderr_mut = Some(socket);
68 }
69 fuzz::TestOutput::Syslog => {
70 let mut syslog_mut = self.syslog.borrow_mut();
71 *syslog_mut = Some(socket);
72 }
73 _ => todo!("not supported"),
74 }
75 zx::Status::OK
76 }
77
78 pub fn get_corpus_type(&self) -> fuzz::Corpus {
80 self.corpus_type.borrow().clone()
81 }
82
83 pub fn set_corpus_type(&self, corpus_type: fuzz::Corpus) {
85 let mut corpus_type_mut = self.corpus_type.borrow_mut();
86 *corpus_type_mut = corpus_type;
87 }
88
89 pub fn take_input_to_send(&self) -> Option<Vec<u8>> {
91 self.input_to_send.borrow_mut().take()
92 }
93
94 pub fn set_input_to_send(&self, input_to_send: &[u8]) {
96 let mut input_to_send_mut = self.input_to_send.borrow_mut();
97 *input_to_send_mut = Some(input_to_send.to_vec());
98 }
99
100 pub fn get_options(&self) -> fuzz::Options {
102 self.options.borrow().clone()
103 }
104
105 pub fn set_options(&self, mut options: fuzz::Options) {
107 add_defaults(&mut options);
108 let mut options_mut = self.options.borrow_mut();
109 *options_mut = options;
110 }
111
112 pub fn get_received_input(&self) -> Vec<u8> {
114 self.received_input.borrow().clone()
115 }
116
117 async fn receive_input(&self, input: FidlInput) -> Result<()> {
119 let mut received_input = Vec::new();
120 let mut reader = fidl::AsyncSocket::from_socket(input.socket);
121 reader.read_to_end(&mut received_input).await?;
122 let mut received_input_mut = self.received_input.borrow_mut();
123 *received_input_mut = received_input;
124 Ok(())
125 }
126
127 pub fn get_result(&self) -> Result<FuzzResult, zx::Status> {
129 self.result.borrow().clone()
130 }
131
132 pub fn set_result(&self, result: Result<FuzzResult, zx::Status>) {
134 let mut result_mut = self.result.borrow_mut();
135 *result_mut = result;
136 }
137
138 pub fn get_status(&self) -> fuzz::Status {
140 self.status.borrow().clone()
141 }
142
143 pub fn set_status(&self, status: fuzz::Status) {
145 let mut status_mut = self.status.borrow_mut();
146 *status_mut = status;
147 }
148
149 async fn send_output(&self, msg: &str) -> Result<()> {
151 let msg_str = format!("{}\n", msg);
152 {
153 let mut stdout_mut = self.stdout.borrow_mut();
154 if let Some(mut stdout) = stdout_mut.take() {
155 stdout.write_all(msg_str.as_bytes()).await?;
156 *stdout_mut = Some(stdout);
157 }
158 }
159 {
160 let mut stderr_mut = self.stderr.borrow_mut();
161 if let Some(mut stderr) = stderr_mut.take() {
162 stderr.write_all(msg_str.as_bytes()).await?;
163 *stderr_mut = Some(stderr);
164 }
165 }
166 {
167 let mut syslog_mut = self.syslog.borrow_mut();
168 if let Some(mut syslog) = syslog_mut.take() {
169 send_log_entry(&mut syslog, msg).await?;
170 *syslog_mut = Some(syslog);
171 }
172 }
173 Ok(())
174 }
175
176 pub fn cancel(&self) {
178 let mut canceled_mut = self.canceled.borrow_mut();
179 *canceled_mut = true;
180 }
181
182 pub fn is_canceled(&self) -> bool {
184 *self.canceled.borrow()
185 }
186}
187
188impl Clone for FakeController {
189 fn clone(&self) -> Self {
190 Self {
191 corpus_type: Rc::clone(&self.corpus_type),
192 input_to_send: Rc::clone(&self.input_to_send),
193 options: Rc::clone(&self.options),
194 received_input: Rc::clone(&self.received_input),
195 result: Rc::clone(&self.result),
196 status: Rc::clone(&self.status),
197 stdout: Rc::clone(&self.stdout),
198 stderr: Rc::clone(&self.stderr),
199 syslog: Rc::clone(&self.syslog),
200 canceled: Rc::clone(&self.canceled),
201 }
202 }
203}
204
205pub async fn serve_controller(
207 mut stream: fuzz::ControllerRequestStream,
208 mut test: Test,
209) -> Result<()> {
210 let fake = test.controller();
211 let mut artifact = Some(FidlArtifact::default());
212 let mut watcher: Option<fuzz::ControllerWatchArtifactResponder> = None;
213 fn reset_artifact(mut watcher: Option<fuzz::ControllerWatchArtifactResponder>) -> Result<()> {
215 if let Some(watcher) = watcher.take() {
216 watcher.send(FidlArtifact::default())?;
217 }
218 Ok(())
219 }
220 loop {
221 let request = stream.next().await;
222 if fake.is_canceled() {
223 break;
224 }
225 match request {
226 Some(Ok(fuzz::ControllerRequest::Configure { options, responder })) => {
227 test.record("fuchsia.fuzzer/Controller.Configure");
228 fake.set_options(options);
229 responder.send(Ok(()))?;
230 }
231 Some(Ok(fuzz::ControllerRequest::GetOptions { responder })) => {
232 test.record("fuchsia.fuzzer/Controller.GetOptions");
233 let options = fake.get_options();
234 responder.send(&options)?;
235 }
236 Some(Ok(fuzz::ControllerRequest::AddToCorpus { corpus, input, responder })) => {
237 test.record(format!("fuchsia.fuzzer/Controller.AddToCorpus({:?})", corpus));
238 fake.receive_input(input).await?;
239 fake.set_corpus_type(corpus);
240 responder.send(Ok(()))?;
241 }
242 Some(Ok(fuzz::ControllerRequest::ReadCorpus { corpus, corpus_reader, responder })) => {
243 test.record("fuchsia.fuzzer/Controller.ReadCorpus");
244 fake.set_corpus_type(corpus);
245 let corpus_reader = corpus_reader.into_proxy();
246 if let Some(input_to_send) = fake.take_input_to_send() {
247 let input_pair = InputPair::try_from_data(input_to_send)?;
248 let (fidl_input, input) = input_pair.as_tuple();
249 let corpus_fut = corpus_reader.next(fidl_input);
250 let input_fut = input.send();
251 let results = join!(corpus_fut, input_fut);
252 assert!(results.0.is_ok());
253 assert!(results.1.is_ok());
254 }
255 responder.send()?;
256 }
257 Some(Ok(fuzz::ControllerRequest::GetStatus { responder })) => {
258 test.record("fuchsia.fuzzer/Controller.GetStatus");
259 let status = fake.get_status();
260 responder.send(&status)?;
261 }
262 Some(Ok(fuzz::ControllerRequest::Fuzz { responder })) => {
263 test.record("fuchsia.fuzzer/Controller.Fuzz");
264 reset_artifact(watcher.take())?;
265 let result = fake.get_result();
269 let options = fake.get_options();
270 match (options.runs, options.max_total_time, result) {
271 (Some(0), Some(0), Ok(FuzzResult::NoErrors))
272 | (_, _, Err(zx::Status::SHOULD_WAIT)) => {
273 let mut status = fake.get_status();
274 status.running = Some(true);
275 fake.set_status(status);
276 responder.send(Ok(()))?;
277 }
278 (_, _, Ok(fuzz_result)) => {
279 let input_to_send = fake.take_input_to_send().unwrap_or(Vec::new());
280 let input_pair = InputPair::try_from_data(input_to_send)?;
281 let (fidl_input, input) = input_pair.as_tuple();
282 artifact = Some(FidlArtifact {
283 result: Some(fuzz_result),
284 input: Some(fidl_input),
285 ..Default::default()
286 });
287 responder.send(Ok(()))?;
288 input.send().await?;
289 fake.send_output(fuzz::DONE_MARKER).await?;
290 }
291 (_, _, Err(status)) => {
292 responder.send(Err(status.into_raw()))?;
293 }
294 };
295 }
296 Some(Ok(fuzz::ControllerRequest::TryOne { test_input, responder })) => {
297 test.record("fuchsia.fuzzer/Controller.TryOne");
298 reset_artifact(watcher.take())?;
299 fake.receive_input(test_input).await?;
300 match fake.get_result() {
301 Ok(fuzz_result) => {
302 artifact = Some(FidlArtifact {
303 result: Some(fuzz_result),
304 input: None,
305 ..Default::default()
306 });
307 responder.send(Ok(()))?;
308 fake.send_output(fuzz::DONE_MARKER).await?;
309 }
310 Err(status) => {
311 responder.send(Err(status.into_raw()))?;
312 }
313 }
314 }
315 Some(Ok(fuzz::ControllerRequest::Minimize { test_input, responder })) => {
316 test.record("fuchsia.fuzzer/Controller.Minimize");
317 reset_artifact(watcher.take())?;
318 fake.receive_input(test_input).await?;
319 let input_to_send = fake.take_input_to_send().context("input_to_send unset")?;
320 let input_pair = InputPair::try_from_data(input_to_send)?;
321 let (fidl_input, input) = input_pair.as_tuple();
322 artifact = Some(FidlArtifact {
323 result: Some(FuzzResult::Minimized),
324 input: Some(fidl_input),
325 ..Default::default()
326 });
327 responder.send(Ok(()))?;
328 input.send().await?;
329 fake.send_output(fuzz::DONE_MARKER).await?;
330 }
331 Some(Ok(fuzz::ControllerRequest::Cleanse { test_input, responder })) => {
332 test.record("fuchsia.fuzzer/Controller.Cleanse");
333 reset_artifact(watcher.take())?;
334 fake.receive_input(test_input).await?;
335 let input_to_send = fake.take_input_to_send().context("input_to_send unset")?;
336 let input_pair = InputPair::try_from_data(input_to_send)?;
337 let (fidl_input, input) = input_pair.as_tuple();
338 artifact = Some(FidlArtifact {
339 result: Some(FuzzResult::Cleansed),
340 input: Some(fidl_input),
341 ..Default::default()
342 });
343 responder.send(Ok(()))?;
344 input.send().await?;
345 fake.send_output(fuzz::DONE_MARKER).await?;
346 }
347 Some(Ok(fuzz::ControllerRequest::Merge { responder })) => {
348 test.record("fuchsia.fuzzer/Controller.Merge");
349 reset_artifact(watcher.take())?;
350 artifact = Some(FidlArtifact {
351 result: Some(FuzzResult::Merged),
352 input: None,
353 ..Default::default()
354 });
355 responder.send(Ok(()))?;
356 fake.send_output(fuzz::DONE_MARKER).await?;
357 }
358 Some(Ok(fuzz::ControllerRequest::WatchArtifact { responder })) => {
359 match artifact.take() {
360 Some(artifact) => {
361 responder.send(artifact)?;
362 }
363 None => {
364 watcher = Some(responder);
365 }
366 };
367 }
368 Some(Err(e)) => return Err(anyhow!(e)),
369 None => break,
370 _ => todo!("not yet implemented"),
371 };
372 }
373 Ok(())
374}