Skip to content

Commit 0bd6de5

Browse files
Merge pull request #256 from microsoft/main
Fork Sync: Update from parent repository
2 parents dfe7f87 + 8cbf66e commit 0bd6de5

File tree

10 files changed

+87
-68
lines changed

10 files changed

+87
-68
lines changed

src/agent/onefuzz-agent/src/validations.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,11 @@ async fn get_logs(config: ValidationConfig) -> Result<()> {
110110
None::<&PathBuf>,
111111
MachineIdentity {
112112
machine_id: Uuid::nil(),
113-
machine_name: "".to_string(),
113+
machine_name: String::new(),
114114
scaleset_name: None,
115115
},
116116
);
117-
let cmd = libfuzzer.build_std_command(None, None, None).await?;
117+
let cmd = libfuzzer.build_std_command(None, None, None, None, None)?;
118118
print_logs(cmd)?;
119119
Ok(())
120120
}

src/agent/onefuzz-task/src/tasks/analysis/generic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ async fn _copy(input_url: BlobUrl, destination_folder: &OwnedDir) -> Result<Path
190190
}
191191
Ok(destination_path)
192192
}
193+
193194
pub async fn run_tool(
194195
input: impl AsRef<Path>,
195196
config: &Config,
@@ -200,7 +201,6 @@ pub async fn run_tool(
200201

201202
let expand = Expand::new(&config.common.machine_identity)
202203
.machine_id()
203-
.await?
204204
.input_path(&input)
205205
.target_exe(&target_exe)
206206
.target_options(&config.target_options)

src/agent/onefuzz-task/src/tasks/coverage/dotnet.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,6 @@ impl<'a> TaskContext<'a> {
295295

296296
let expand = Expand::new(&self.config.common.machine_identity)
297297
.machine_id()
298-
.await?
299298
.input_path(input)
300299
.job_id(&self.config.common.job_id)
301300
.setup_dir(&self.config.common.setup_dir)

src/agent/onefuzz-task/src/tasks/coverage/generic.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,6 @@ impl<'a> TaskContext<'a> {
295295

296296
let expand = Expand::new(&self.config.common.machine_identity)
297297
.machine_id()
298-
.await?
299298
.input_path(input)
300299
.job_id(&self.config.common.job_id)
301300
.setup_dir(&self.config.common.setup_dir)

src/agent/onefuzz-task/src/tasks/fuzz/generator.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,6 @@ impl GeneratorTask {
167167
let (mut generator, generator_path) = {
168168
let expand = Expand::new(&self.config.common.machine_identity)
169169
.machine_id()
170-
.await?
171170
.setup_dir(&self.config.common.setup_dir)
172171
.set_optional_ref(&self.config.common.extra_dir, |expand, extra_dir| {
173172
expand.extra_dir(extra_dir)

src/agent/onefuzz-task/src/tasks/fuzz/supervisor.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,6 @@ pub async fn spawn(config: SupervisorConfig) -> Result<(), Error> {
146146
Some(
147147
Expand::new(&config.common.machine_identity)
148148
.machine_id()
149-
.await?
150149
.runtime_dir(runtime_dir.path())
151150
.evaluate_value(stats_file)?,
152151
)
@@ -206,7 +205,6 @@ async fn start_supervisor(
206205

207206
let expand = Expand::new(&config.common.machine_identity)
208207
.machine_id()
209-
.await?
210208
.supervisor_exe(&config.supervisor_exe)
211209
.supervisor_options(&config.supervisor_options)
212210
.runtime_dir(&runtime_dir)

src/agent/onefuzz-task/src/tasks/merge/generic.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@ async fn merge(config: &Config, output_dir: impl AsRef<Path>) -> Result<()> {
132132

133133
let expand = Expand::new(&config.common.machine_identity)
134134
.machine_id()
135-
.await?
136135
.input_marker(&config.supervisor_input_marker)
137136
.input_corpus(&config.unique_inputs.local_path)
138137
.target_options(&config.target_options)

src/agent/onefuzz/src/expand.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,10 @@ impl<'a> Expand<'a> {
116116
}
117117
}
118118

119-
// Must be manually called to enable the use of async library code.
120-
pub async fn machine_id(self) -> Result<Expand<'a>> {
119+
pub fn machine_id(self) -> Expand<'a> {
121120
let id = self.machine_identity.machine_id;
122121
let value = id.to_string();
123-
Ok(self.set_value(PlaceHolder::MachineId, ExpandedValue::Scalar(value)))
122+
self.set_value(PlaceHolder::MachineId, ExpandedValue::Scalar(value))
124123
}
125124

126125
fn input_file_sha256(&self) -> Result<ExpandedValue<'a>> {
@@ -742,7 +741,7 @@ mod tests {
742741
async fn test_expand_machine_id() -> Result<()> {
743742
let machine_identity = &test_machine_identity();
744743
let machine_id = machine_identity.machine_id;
745-
let expand = Expand::new(machine_identity).machine_id().await?;
744+
let expand = Expand::new(machine_identity).machine_id();
746745
let expanded = expand.evaluate_value("{machine_id}")?;
747746
// Check that "{machine_id}" expands to a valid UUID, but don't worry about the actual value.
748747
let expanded_machine_id = Uuid::parse_str(&expanded)?;

src/agent/onefuzz/src/input_tester.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,6 @@ impl<'a> Tester<'a> {
297297
let (argv, env) = {
298298
let expand = Expand::new(&self.machine_identity)
299299
.machine_id()
300-
.await?
301300
.input_path(input_file)
302301
.target_exe(self.exe_path)
303302
.target_options(self.arguments)

src/agent/onefuzz/src/libfuzzer.rs

Lines changed: 81 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rand::seq::SliceRandom;
1313
use rand::thread_rng;
1414
use std::{
1515
collections::HashMap,
16-
ffi::OsString,
16+
ffi::{OsStr, OsString},
1717
path::{Path, PathBuf},
1818
process::Stdio,
1919
};
@@ -64,17 +64,23 @@ impl LibFuzzer {
6464
}
6565

6666
// Build an async `Command`.
67-
async fn build_command(
67+
fn build_command(
6868
&self,
6969
fault_dir: Option<&Path>,
7070
corpus_dir: Option<&Path>,
7171
extra_corpus_dirs: Option<&[&Path]>,
72+
extra_args: Option<&[&OsStr]>,
73+
custom_arg_filter: Option<&dyn Fn(String) -> Option<String>>,
7274
) -> Result<Command> {
73-
let std_cmd = self
74-
.build_std_command(fault_dir, corpus_dir, extra_corpus_dirs)
75-
.await?;
76-
77-
// Make async.
75+
let std_cmd = self.build_std_command(
76+
fault_dir,
77+
corpus_dir,
78+
extra_corpus_dirs,
79+
extra_args,
80+
custom_arg_filter,
81+
)?;
82+
83+
// Make async (turn into tokio::process::Command):
7884
let mut cmd = Command::from(std_cmd);
7985

8086
// Terminate the process if the `Child` handle is dropped.
@@ -84,11 +90,13 @@ impl LibFuzzer {
8490
}
8591

8692
// Build a non-async `Command`.
87-
pub async fn build_std_command(
93+
pub fn build_std_command(
8894
&self,
8995
fault_dir: Option<&Path>,
9096
corpus_dir: Option<&Path>,
9197
extra_corpus_dirs: Option<&[&Path]>,
98+
extra_args: Option<&[&OsStr]>,
99+
custom_arg_filter: Option<&dyn Fn(String) -> Option<String>>,
92100
) -> Result<std::process::Command> {
93101
let mut cmd = std::process::Command::new(&self.exe);
94102
cmd.env(PATH, get_path_with_directory(PATH, &self.setup_dir)?)
@@ -107,38 +115,36 @@ impl LibFuzzer {
107115

108116
let expand = Expand::new(&self.machine_identity)
109117
.machine_id()
110-
.await?
111118
.target_exe(&self.exe)
112119
.target_options(&self.options)
113120
.setup_dir(&self.setup_dir)
114-
.set_optional(self.extra_dir.as_ref(), |expand, extra_dir| {
115-
expand.extra_dir(extra_dir)
116-
})
117-
.set_optional(corpus_dir, |e, corpus_dir| e.input_corpus(corpus_dir))
118-
.set_optional(fault_dir, |e, fault_dir| e.crashes(fault_dir));
121+
.set_optional(self.extra_dir.as_ref(), Expand::extra_dir)
122+
.set_optional(corpus_dir, Expand::input_corpus)
123+
.set_optional(fault_dir, Expand::crashes);
119124

125+
// Expand and set environment variables:
120126
for (k, v) in &self.env {
121127
cmd.env(k, expand.evaluate_value(v)?);
122128
}
123129

124-
// Pass custom option arguments.
125-
for o in expand.evaluate(&self.options)? {
126-
cmd.arg(o);
127-
}
128-
129-
// Set the read/written main corpus directory.
130+
// Set the read/written main corpus directory:
130131
if let Some(corpus_dir) = corpus_dir {
131132
cmd.arg(corpus_dir);
132133
}
133134

134-
// Set extra corpus directories that will be periodically rescanned.
135+
// Set extra (readonly) corpus directories that will also be used:
135136
if let Some(extra_corpus_dirs) = extra_corpus_dirs {
136-
for dir in extra_corpus_dirs {
137-
cmd.arg(dir);
138-
}
137+
cmd.args(extra_corpus_dirs);
139138
}
140139

141-
// check if a max_time is already set
140+
// Pass any extra arguments that we need; this is done in this function
141+
// rather than the caller so that they can come before any custom options
142+
// that might interfere (e.g. -help=1 must come before -ignore_remaining_args=1).
143+
if let Some(extra_args) = extra_args {
144+
cmd.args(extra_args);
145+
}
146+
147+
// Check if a max time is already set by the custom options, and set if not:
142148
if !self
143149
.options
144150
.iter()
@@ -147,6 +153,18 @@ impl LibFuzzer {
147153
cmd.arg(format!("-max_total_time={DEFAULT_MAX_TOTAL_SECONDS}"));
148154
}
149155

156+
// Pass custom option arguments last, to lessen the chance that they
157+
// interfere with standard options (e.g. use of -ignore_remaining_args=1),
158+
// and also to allow last-one-wins overriding if needed.
159+
//
160+
// We also allow filtering out parameters as well:
161+
cmd.args(
162+
expand
163+
.evaluate(&self.options)?
164+
.into_iter()
165+
.filter_map(custom_arg_filter.unwrap_or(&Some)),
166+
);
167+
150168
Ok(cmd)
151169
}
152170

@@ -194,28 +212,35 @@ impl LibFuzzer {
194212
Ok(())
195213
}
196214

215+
// Verify that the libfuzzer exits with a zero return code with a known
216+
// good input, which libfuzzer works as we expect.
197217
async fn check_input(&self, input: &Path) -> Result<()> {
198-
// Verify that the libfuzzer exits with a zero return code with a known
199-
// good input, which libfuzzer works as we expect.
200-
201-
let mut cmd = self.build_command(None, None, None).await?;
202-
203-
// Override any arg of the form `-runs=<N>` (last occurrence wins).
204-
// In this command invocation, we only ever want to test inputs once.
205-
//
206-
// Assumes that the presence of an `-args` option was an iteration limit meant
207-
// for fuzzing mode. We are only mutating the args of a local `Command`, so the
208-
// command used by the `fuzz()` method will still receive the iteration limit.
209-
cmd.arg("-runs=1");
210-
211-
cmd.arg(input);
218+
let mut cmd = self.build_command(
219+
None,
220+
None,
221+
None,
222+
// Custom args for this run: supply the required input. In this mode,
223+
// LibFuzzer will only execute one run of fuzzing unless overridden
224+
Some(&[input.as_ref()]),
225+
// Filter out any argument starting with `-runs=` from the custom
226+
// target options, if supplied, so that it doesn't make more than
227+
// one run happen:
228+
Some(&|arg: String| {
229+
if arg.starts_with("-runs=") {
230+
None
231+
} else {
232+
Some(arg)
233+
}
234+
}),
235+
)?;
212236

213237
let result = cmd
214238
.spawn()
215239
.with_context(|| format_err!("libfuzzer failed to start: {}", self.exe.display()))?
216240
.wait_with_output()
217241
.await
218242
.with_context(|| format_err!("libfuzzer failed to run: {}", self.exe.display()))?;
243+
219244
if !result.status.success() {
220245
bail!(
221246
"libFuzzer failed when parsing an initial seed {:?}: stdout:{:?} stderr:{:?}",
@@ -224,15 +249,15 @@ impl LibFuzzer {
224249
String::from_utf8_lossy(&result.stderr),
225250
);
226251
}
252+
227253
Ok(())
228254
}
229255

230256
/// Invoke `{target_exe} -help=1`. If this succeeds, then the dynamic linker is at
231257
/// least able to satisfy the fuzzer's shared library dependencies. User-authored
232258
/// dynamic loading may still fail later on, e.g. in `LLVMFuzzerInitialize()`.
233259
async fn check_help(&self) -> Result<()> {
234-
let mut cmd = self.build_command(None, None, None).await?;
235-
cmd.arg("-help=1");
260+
let mut cmd = self.build_command(None, None, None, Some(&["-help=1".as_ref()]), None)?;
236261

237262
let result = cmd
238263
.spawn()
@@ -263,7 +288,7 @@ impl LibFuzzer {
263288
}
264289

265290
async fn find_missing_libraries(&self) -> Result<Vec<String>> {
266-
let cmd = self.build_std_command(None, None, None).await?;
291+
let cmd = self.build_std_command(None, None, None, None, None)?;
267292

268293
#[cfg(target_os = "linux")]
269294
let blocking = move || dynamic_library::linux::find_missing(cmd);
@@ -284,13 +309,6 @@ impl LibFuzzer {
284309
extra_corpus_dirs: &[impl AsRef<Path>],
285310
) -> Result<Child> {
286311
let extra_corpus_dirs: Vec<&Path> = extra_corpus_dirs.iter().map(|x| x.as_ref()).collect();
287-
let mut cmd = self
288-
.build_command(
289-
Some(fault_dir.as_ref()),
290-
Some(corpus_dir.as_ref()),
291-
Some(&extra_corpus_dirs),
292-
)
293-
.await?;
294312

295313
// When writing a new faulting input, the libFuzzer runtime _exactly_
296314
// prepends the value of `-artifact_prefix` to the new file name. To
@@ -300,7 +318,13 @@ impl LibFuzzer {
300318
let artifact_prefix: OsString =
301319
format!("-artifact_prefix={}/", fault_dir.as_ref().display()).into();
302320

303-
cmd.arg(&artifact_prefix);
321+
let mut cmd = self.build_command(
322+
Some(fault_dir.as_ref()),
323+
Some(corpus_dir.as_ref()),
324+
Some(&extra_corpus_dirs),
325+
Some(&[&artifact_prefix]),
326+
None,
327+
)?;
304328

305329
let child = cmd
306330
.spawn()
@@ -344,10 +368,13 @@ impl LibFuzzer {
344368
extra_corpus_dirs: &[impl AsRef<Path>],
345369
) -> Result<LibFuzzerMergeOutput> {
346370
let extra_corpus_dirs: Vec<&Path> = extra_corpus_dirs.iter().map(|x| x.as_ref()).collect();
347-
let mut cmd = self
348-
.build_command(None, Some(corpus_dir.as_ref()), Some(&extra_corpus_dirs))
349-
.await?;
350-
cmd.arg("-merge=1");
371+
let mut cmd = self.build_command(
372+
None,
373+
Some(corpus_dir.as_ref()),
374+
Some(&extra_corpus_dirs),
375+
Some(&["-merge=1".as_ref()]),
376+
None,
377+
)?;
351378

352379
let output = cmd
353380
.spawn()

0 commit comments

Comments
 (0)