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