mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-18 04:38:09 +00:00
Adding extra container to tasks (#2847)
* adding extra container to tasks * setup expand * build fix * generate docs * build fix * build fix * build fix * format * format * build fix * fix extra container references * format * Update "Needs Triage" label to the one we use. (#2845) * Report extension errors (#2846) Old failure message: ``` failed to launch extension ``` New failure message: ``` failed to launch extension(s): Errors for extension 'CustomScriptExtension': :Error: ProvisioningState/failed/3 (Provisioning failed) - Failed to download all specified files. Exiting. Error Message: The remote server returned an error: (400) Bad Request. ``` * Sematically validate notification configs (#2850) * Add new command * Update remaining jinja templates and references to use scriban * Add ado template validation * Validate ado and github templates * Remove unnecessary function * Update src/ApiService/ApiService/OneFuzzTypes/Model.cs Co-authored-by: Cheick Keita <kcheick@gmail.com> --------- Co-authored-by: Cheick Keita <kcheick@gmail.com> * adding extra container to integration tests * adding doc * update tests * format * build and clippy fix * Update src/agent/onefuzz-task/src/tasks/report/generic.rs Co-authored-by: Teo Voinea <58236992+tevoinea@users.noreply.github.com> --------- Co-authored-by: Marc Greisen <mgreisen@microsoft.com> Co-authored-by: George Pollard <gpollard@microsoft.com> Co-authored-by: Teo Voinea <58236992+tevoinea@users.noreply.github.com>
This commit is contained in:
@ -26,6 +26,7 @@ The following values are replaced with the specific values at runtime.
|
||||
* `{crashes_container}`: Container name for the `crashes` container
|
||||
* `{microsoft_telemetry_key}`: Application Insights key used for collecting [non-attributable telemetry](telemetry.md) to improve OneFuzz.
|
||||
* `{instance_telemetry_key}`: Application Insights key used for private, instance-owned telemetry and logging (See [OneFuzz Telemetry](telemetry.md).
|
||||
* `{extra}`: Path to the optionally provided `extra` directory
|
||||
|
||||
## Example
|
||||
|
||||
|
@ -151,7 +151,8 @@ If webhook is set to have Event Grid message format then the payload will look a
|
||||
"unique_inputs",
|
||||
"unique_reports",
|
||||
"regression_reports",
|
||||
"logs"
|
||||
"logs",
|
||||
"extra"
|
||||
],
|
||||
"title": "ContainerType"
|
||||
},
|
||||
@ -2001,7 +2002,8 @@ If webhook is set to have Event Grid message format then the payload will look a
|
||||
"unique_inputs",
|
||||
"unique_reports",
|
||||
"regression_reports",
|
||||
"logs"
|
||||
"logs",
|
||||
"extra"
|
||||
],
|
||||
"title": "ContainerType"
|
||||
},
|
||||
@ -2927,7 +2929,8 @@ If webhook is set to have Event Grid message format then the payload will look a
|
||||
"unique_inputs",
|
||||
"unique_reports",
|
||||
"regression_reports",
|
||||
"logs"
|
||||
"logs",
|
||||
"extra"
|
||||
],
|
||||
"title": "ContainerType"
|
||||
},
|
||||
@ -3408,7 +3411,8 @@ If webhook is set to have Event Grid message format then the payload will look a
|
||||
"unique_inputs",
|
||||
"unique_reports",
|
||||
"regression_reports",
|
||||
"logs"
|
||||
"logs",
|
||||
"extra"
|
||||
],
|
||||
"title": "ContainerType"
|
||||
},
|
||||
@ -3932,7 +3936,8 @@ If webhook is set to have Event Grid message format then the payload will look a
|
||||
"unique_inputs",
|
||||
"unique_reports",
|
||||
"regression_reports",
|
||||
"logs"
|
||||
"logs",
|
||||
"extra"
|
||||
],
|
||||
"title": "ContainerType"
|
||||
},
|
||||
@ -4380,7 +4385,8 @@ If webhook is set to have Event Grid message format then the payload will look a
|
||||
"unique_inputs",
|
||||
"unique_reports",
|
||||
"regression_reports",
|
||||
"logs"
|
||||
"logs",
|
||||
"extra"
|
||||
],
|
||||
"title": "ContainerType"
|
||||
},
|
||||
@ -4855,7 +4861,8 @@ If webhook is set to have Event Grid message format then the payload will look a
|
||||
"unique_inputs",
|
||||
"unique_reports",
|
||||
"regression_reports",
|
||||
"logs"
|
||||
"logs",
|
||||
"extra"
|
||||
],
|
||||
"title": "ContainerType"
|
||||
},
|
||||
@ -5460,7 +5467,8 @@ If webhook is set to have Event Grid message format then the payload will look a
|
||||
"unique_inputs",
|
||||
"unique_reports",
|
||||
"regression_reports",
|
||||
"logs"
|
||||
"logs",
|
||||
"extra"
|
||||
],
|
||||
"title": "ContainerType"
|
||||
},
|
||||
|
@ -98,7 +98,8 @@ public enum ContainerType {
|
||||
UniqueInputs,
|
||||
UniqueReports,
|
||||
RegressionReports,
|
||||
Logs
|
||||
Logs,
|
||||
Extra
|
||||
}
|
||||
|
||||
|
||||
|
@ -893,6 +893,7 @@ public record TaskDefinition(
|
||||
public record WorkSet(
|
||||
bool Reboot,
|
||||
Uri SetupUrl,
|
||||
Uri? ExtraUrl,
|
||||
bool Script,
|
||||
List<WorkUnit> WorkUnits
|
||||
);
|
||||
@ -1020,6 +1021,7 @@ public record TaskUnitConfig(
|
||||
public IContainerDef? UniqueInputs { get; set; }
|
||||
public IContainerDef? UniqueReports { get; set; }
|
||||
public IContainerDef? RegressionReports { get; set; }
|
||||
public IContainerDef? Extra { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
@ -140,6 +140,9 @@ public class Config : IConfig {
|
||||
case ContainerType.RegressionReports:
|
||||
config.RegressionReports = def;
|
||||
break;
|
||||
case ContainerType.Extra:
|
||||
config.Extra = def;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,14 @@ public static class Defs {
|
||||
ContainerPermission.List |
|
||||
ContainerPermission.Read |
|
||||
ContainerPermission.Write
|
||||
)},
|
||||
),
|
||||
new ContainerDefinition(
|
||||
Type:ContainerType.Extra,
|
||||
Compare: Compare.AtMost,
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
},
|
||||
MonitorQueue: ContainerType.ReadonlyInputs)
|
||||
},
|
||||
{
|
||||
@ -83,6 +90,12 @@ public static class Defs {
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
new ContainerDefinition(
|
||||
Type:ContainerType.Extra,
|
||||
Compare: Compare.AtMost,
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
},
|
||||
MonitorQueue: ContainerType.ReadonlyInputs)
|
||||
},
|
||||
@ -135,6 +148,12 @@ public static class Defs {
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
new ContainerDefinition(
|
||||
Type:ContainerType.Extra,
|
||||
Compare: Compare.AtMost,
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
},
|
||||
MonitorQueue: ContainerType.Crashes
|
||||
)
|
||||
@ -185,6 +204,12 @@ public static class Defs {
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
new ContainerDefinition(
|
||||
Type:ContainerType.Extra,
|
||||
Compare: Compare.AtMost,
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
}
|
||||
)},
|
||||
{ TaskType.GenericAnalysis ,
|
||||
@ -222,6 +247,12 @@ public static class Defs {
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
new ContainerDefinition(
|
||||
Type:ContainerType.Extra,
|
||||
Compare: Compare.AtMost,
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
},
|
||||
MonitorQueue: ContainerType.Crashes)
|
||||
},
|
||||
@ -264,6 +295,12 @@ public static class Defs {
|
||||
Value: 0,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
new ContainerDefinition(
|
||||
Type:ContainerType.Extra,
|
||||
Compare: Compare.AtMost,
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
}
|
||||
)},
|
||||
{
|
||||
@ -309,6 +346,12 @@ public static class Defs {
|
||||
Value: 1,
|
||||
Permissions: ContainerPermission.Write
|
||||
),
|
||||
new ContainerDefinition(
|
||||
Type:ContainerType.Extra,
|
||||
Compare: Compare.AtMost,
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
},
|
||||
MonitorQueue: ContainerType.Crashes
|
||||
)
|
||||
@ -343,7 +386,16 @@ public static class Defs {
|
||||
ContainerPermission.List |
|
||||
ContainerPermission.Read |
|
||||
ContainerPermission.Write
|
||||
)},
|
||||
),
|
||||
new ContainerDefinition(
|
||||
Type:ContainerType.Extra,
|
||||
Compare: Compare.AtMost,
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
|
||||
|
||||
},
|
||||
MonitorQueue: ContainerType.ReadonlyInputs
|
||||
)},
|
||||
{
|
||||
@ -377,6 +429,12 @@ public static class Defs {
|
||||
Value: 0,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
new ContainerDefinition(
|
||||
Type:ContainerType.Extra,
|
||||
Compare: Compare.AtMost,
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
}
|
||||
)
|
||||
},
|
||||
@ -445,6 +503,12 @@ public static class Defs {
|
||||
Value: 1,
|
||||
Permissions: ContainerPermission.Write | ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
new ContainerDefinition(
|
||||
Type:ContainerType.Extra,
|
||||
Compare: Compare.AtMost,
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
}
|
||||
)
|
||||
},
|
||||
@ -486,6 +550,12 @@ public static class Defs {
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Write| ContainerPermission.List
|
||||
),
|
||||
new ContainerDefinition(
|
||||
Type:ContainerType.Extra,
|
||||
Compare: Compare.AtMost,
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
}
|
||||
)
|
||||
},
|
||||
@ -532,6 +602,12 @@ public static class Defs {
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
new ContainerDefinition(
|
||||
Type:ContainerType.Extra,
|
||||
Compare: Compare.AtMost,
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
}
|
||||
)
|
||||
},
|
||||
@ -579,6 +655,12 @@ public static class Defs {
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Write
|
||||
),
|
||||
new ContainerDefinition(
|
||||
Type:ContainerType.Extra,
|
||||
Compare: Compare.AtMost,
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
},
|
||||
MonitorQueue: ContainerType.Crashes
|
||||
)
|
||||
@ -640,6 +722,12 @@ public static class Defs {
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
new ContainerDefinition(
|
||||
Type:ContainerType.Extra,
|
||||
Compare: Compare.AtMost,
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
})
|
||||
},
|
||||
{
|
||||
@ -699,6 +787,12 @@ public static class Defs {
|
||||
Permissions:
|
||||
ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
new ContainerDefinition(
|
||||
Type:ContainerType.Extra,
|
||||
Compare: Compare.AtMost,
|
||||
Value:1,
|
||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||
),
|
||||
})
|
||||
},
|
||||
};
|
||||
|
@ -104,10 +104,12 @@ public class Scheduler : IScheduler {
|
||||
|
||||
if (bucketConfig is not null) {
|
||||
var setupUrl = await _containers.GetContainerSasUrl(bucketConfig.setupContainer, StorageType.Corpus, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
|
||||
var extraUrl = bucketConfig.extraContainer != null ? await _containers.GetContainerSasUrl(bucketConfig.extraContainer, StorageType.Corpus, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List) : null;
|
||||
var workSet = new WorkSet(
|
||||
Reboot: bucketConfig.reboot,
|
||||
Script: bucketConfig.setupScript is not null,
|
||||
SetupUrl: setupUrl,
|
||||
ExtraUrl: extraUrl,
|
||||
WorkUnits: workUnits
|
||||
);
|
||||
|
||||
@ -118,7 +120,7 @@ public class Scheduler : IScheduler {
|
||||
}
|
||||
|
||||
|
||||
sealed record BucketConfig(long count, bool reboot, Container setupContainer, string? setupScript, Pool pool);
|
||||
sealed record BucketConfig(long count, bool reboot, Container setupContainer, Container? extraContainer, string? setupScript, Pool pool);
|
||||
|
||||
sealed record PoolKey(
|
||||
PoolName? poolName = null,
|
||||
@ -172,6 +174,8 @@ public class Scheduler : IScheduler {
|
||||
}
|
||||
var setupContainer = task.Config.Containers?.FirstOrDefault(c => c.Type == ContainerType.Setup) ?? throw new Exception($"task missing setup container: task_type = {task.Config.Task.Type}");
|
||||
|
||||
var extraContainer = task.Config.Containers?.FirstOrDefault(c => c.Type == ContainerType.Extra);
|
||||
|
||||
string? setupScript = null;
|
||||
if (task.Os == Os.Windows) {
|
||||
if (await _containers.BlobExists(setupContainer.Name, "setup.ps1", StorageType.Corpus)) {
|
||||
@ -209,6 +213,7 @@ public class Scheduler : IScheduler {
|
||||
count,
|
||||
reboot,
|
||||
setupContainer.Name,
|
||||
extraContainer?.Name,
|
||||
setupScript,
|
||||
pool with { ETag = default, TimeStamp = default });
|
||||
|
||||
|
@ -129,7 +129,7 @@ pub fn find_coverage_sites(
|
||||
|
||||
// Apply allowlists per block, to account for inlining. The `location` values
|
||||
// here describe the top of the inline-inclusive call stack.
|
||||
if !allowlist.source_files.is_allowed(&path) {
|
||||
if !allowlist.source_files.is_allowed(path) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -60,6 +60,7 @@ impl Fixture {
|
||||
WorkSet {
|
||||
reboot: false,
|
||||
setup_url: self.setup_url(),
|
||||
extra_url: None,
|
||||
script: false,
|
||||
work_units: vec![self.work_unit()],
|
||||
}
|
||||
|
@ -143,6 +143,9 @@ pub struct RunWorkerOpt {
|
||||
|
||||
#[clap(long)]
|
||||
script: bool,
|
||||
|
||||
#[clap(long)]
|
||||
extra_url: Option<Url>,
|
||||
}
|
||||
|
||||
fn debug_run_worker(opt: RunWorkerOpt) -> Result<()> {
|
||||
@ -164,6 +167,7 @@ fn debug_run_worker(opt: RunWorkerOpt) -> Result<()> {
|
||||
let work_set = WorkSet {
|
||||
reboot: false,
|
||||
setup_url: BlobContainerUrl::new(opt.setup_url)?,
|
||||
extra_url: opt.extra_url.map(BlobContainerUrl::new).transpose()?,
|
||||
script: opt.script,
|
||||
work_units: vec![work_unit],
|
||||
};
|
||||
@ -188,8 +192,9 @@ async fn run_worker(mut work_set: WorkSet) -> Result<Vec<WorkerEvent>> {
|
||||
let mut events = vec![];
|
||||
let work_unit = work_set.work_units.pop().unwrap();
|
||||
let setup_dir = work_set.setup_dir()?;
|
||||
let extra_dir = work_set.extra_dir()?;
|
||||
|
||||
let mut worker = Worker::new(&setup_dir, work_unit);
|
||||
let mut worker = Worker::new(&setup_dir, extra_dir, work_unit);
|
||||
while !worker.is_done() {
|
||||
worker = worker
|
||||
.update(
|
||||
|
@ -250,8 +250,9 @@ impl State<Ready> {
|
||||
pub async fn run(self) -> Result<State<Busy>> {
|
||||
let mut workers = vec![];
|
||||
let setup_dir = &self.ctx.work_set.setup_dir()?;
|
||||
let extra_dir = self.ctx.work_set.extra_dir()?;
|
||||
for work in self.ctx.work_set.work_units {
|
||||
let worker = Some(Worker::new(setup_dir, work));
|
||||
let worker = Some(Worker::new(setup_dir, extra_dir.clone(), work));
|
||||
workers.push(worker);
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,20 @@ pub struct SetupRunner {
|
||||
|
||||
impl SetupRunner {
|
||||
pub async fn run(&self, work_set: &WorkSet) -> Result<SetupOutput> {
|
||||
if let (Some(extra_url), Some(extra_dir)) = (&work_set.extra_url, work_set.extra_dir()?) {
|
||||
info!("downloading extra container");
|
||||
// `azcopy sync` requires the local dir to exist.
|
||||
fs::create_dir_all(&extra_dir).await.with_context(|| {
|
||||
format!("unable to create extra container: {}", extra_dir.display())
|
||||
})?;
|
||||
az_copy::sync(extra_url.to_string(), &extra_dir, false).await?;
|
||||
debug!(
|
||||
"synced extra container from {} to {}",
|
||||
extra_url,
|
||||
extra_dir.display(),
|
||||
);
|
||||
}
|
||||
|
||||
info!("running setup for work set");
|
||||
work_set.save_context(self.machine_id).await?;
|
||||
// Download the setup container.
|
||||
|
@ -22,6 +22,7 @@ pub type TaskId = Uuid;
|
||||
pub struct WorkSet {
|
||||
pub reboot: bool,
|
||||
pub setup_url: BlobContainerUrl,
|
||||
pub extra_url: Option<BlobContainerUrl>,
|
||||
pub script: bool,
|
||||
pub work_units: Vec<WorkUnit>,
|
||||
}
|
||||
@ -92,6 +93,21 @@ impl WorkSet {
|
||||
.join("blob-containers")
|
||||
.join(setup_dir))
|
||||
}
|
||||
|
||||
pub fn extra_dir(&self) -> Result<Option<PathBuf>> {
|
||||
if let Some(extra_url) = &self.extra_url {
|
||||
let extra_dir = extra_url
|
||||
.account()
|
||||
.ok_or_else(|| anyhow!("Invalid container Url"))?;
|
||||
Ok(Some(
|
||||
onefuzz::fs::onefuzz_root()?
|
||||
.join("blob-containers")
|
||||
.join(extra_dir),
|
||||
))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
|
@ -45,9 +45,14 @@ pub enum Worker {
|
||||
}
|
||||
|
||||
impl Worker {
|
||||
pub fn new(setup_dir: impl AsRef<Path>, work: WorkUnit) -> Self {
|
||||
pub fn new(
|
||||
setup_dir: impl AsRef<Path>,
|
||||
extra_dir: Option<impl AsRef<Path>>,
|
||||
work: WorkUnit,
|
||||
) -> Self {
|
||||
let ctx = Ready {
|
||||
setup_dir: PathBuf::from(setup_dir.as_ref()),
|
||||
extra_dir: extra_dir.map(|dir| PathBuf::from(dir.as_ref())),
|
||||
};
|
||||
let state = State { ctx, work };
|
||||
state.into()
|
||||
@ -98,6 +103,7 @@ impl Worker {
|
||||
#[derive(Debug)]
|
||||
pub struct Ready {
|
||||
setup_dir: PathBuf,
|
||||
extra_dir: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -130,7 +136,9 @@ impl<C: Context> State<C> {
|
||||
|
||||
impl State<Ready> {
|
||||
pub async fn run(self, runner: &mut dyn IWorkerRunner) -> Result<State<Running>> {
|
||||
let child = runner.run(&self.ctx.setup_dir, &self.work).await?;
|
||||
let child = runner
|
||||
.run(&self.ctx.setup_dir, self.ctx.extra_dir, &self.work)
|
||||
.await?;
|
||||
|
||||
let state = State {
|
||||
ctx: Running { child },
|
||||
@ -189,7 +197,12 @@ impl_from_state_for_worker!(Done);
|
||||
|
||||
#[async_trait]
|
||||
pub trait IWorkerRunner: Downcast {
|
||||
async fn run(&self, setup_dir: &Path, work: &WorkUnit) -> Result<Box<dyn IWorkerChild>>;
|
||||
async fn run(
|
||||
&self,
|
||||
setup_dir: &Path,
|
||||
extra_dir: Option<PathBuf>,
|
||||
work: &WorkUnit,
|
||||
) -> Result<Box<dyn IWorkerChild>>;
|
||||
}
|
||||
|
||||
impl_downcast!(IWorkerRunner);
|
||||
@ -214,7 +227,12 @@ impl WorkerRunner {
|
||||
|
||||
#[async_trait]
|
||||
impl IWorkerRunner for WorkerRunner {
|
||||
async fn run(&self, setup_dir: &Path, work: &WorkUnit) -> Result<Box<dyn IWorkerChild>> {
|
||||
async fn run(
|
||||
&self,
|
||||
setup_dir: &Path,
|
||||
extra_dir: Option<PathBuf>,
|
||||
work: &WorkUnit,
|
||||
) -> Result<Box<dyn IWorkerChild>> {
|
||||
let working_dir = work.working_dir(self.machine_identity.machine_id)?;
|
||||
|
||||
debug!("worker working dir = {}", working_dir.display());
|
||||
@ -260,6 +278,11 @@ impl IWorkerRunner for WorkerRunner {
|
||||
cmd.arg("managed");
|
||||
cmd.arg("config.json");
|
||||
cmd.arg(setup_dir);
|
||||
if let Some(extra_dir) = extra_dir {
|
||||
cmd.arg("--extra_dir");
|
||||
cmd.arg(extra_dir);
|
||||
}
|
||||
|
||||
cmd.stderr(Stdio::piped());
|
||||
cmd.stdout(Stdio::piped());
|
||||
|
||||
|
@ -10,7 +10,12 @@ pub struct WorkerRunnerDouble {
|
||||
|
||||
#[async_trait]
|
||||
impl IWorkerRunner for WorkerRunnerDouble {
|
||||
async fn run(&self, _setup_dir: &Path, _work: &WorkUnit) -> Result<Box<dyn IWorkerChild>> {
|
||||
async fn run(
|
||||
&self,
|
||||
_setup_dir: &Path,
|
||||
_extra_dir: Option<PathBuf>,
|
||||
_work: &WorkUnit,
|
||||
) -> Result<Box<dyn IWorkerChild>> {
|
||||
Ok(Box::new(self.child.clone()))
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,12 @@ struct RunnerDouble {
|
||||
|
||||
#[async_trait]
|
||||
impl IWorkerRunner for RunnerDouble {
|
||||
async fn run(&self, _setup_dir: &Path, _work: &WorkUnit) -> Result<Box<dyn IWorkerChild>> {
|
||||
async fn run(
|
||||
&self,
|
||||
_setup_dir: &Path,
|
||||
_extra_dir: Option<PathBuf>,
|
||||
_work: &WorkUnit,
|
||||
) -> Result<Box<dyn IWorkerChild>> {
|
||||
Ok(Box::new(self.child.clone()))
|
||||
}
|
||||
}
|
||||
@ -66,6 +71,7 @@ async fn test_ready_run() {
|
||||
let state = State {
|
||||
ctx: Ready {
|
||||
setup_dir: PathBuf::default(),
|
||||
extra_dir: None,
|
||||
},
|
||||
work: Fixture.work(),
|
||||
};
|
||||
@ -148,6 +154,7 @@ async fn test_worker_ready_update() {
|
||||
let state = State {
|
||||
ctx: Ready {
|
||||
setup_dir: PathBuf::default(),
|
||||
extra_dir: None,
|
||||
},
|
||||
work: Fixture.work(),
|
||||
};
|
||||
|
@ -22,6 +22,7 @@ use crate::tasks::config::CommonConfig;
|
||||
use crate::tasks::utils::parse_key_value;
|
||||
|
||||
pub const SETUP_DIR: &str = "setup_dir";
|
||||
pub const EXTRA_DIR: &str = "extra_dir";
|
||||
pub const INPUTS_DIR: &str = "inputs_dir";
|
||||
pub const CRASHES_DIR: &str = "crashes_dir";
|
||||
pub const TARGET_WORKERS: &str = "target_workers";
|
||||
@ -237,6 +238,7 @@ pub async fn build_local_context(
|
||||
});
|
||||
let instance_id = get_uuid("instance_id", args).unwrap_or_default();
|
||||
|
||||
let extra_dir = args.get_one::<PathBuf>(EXTRA_DIR).cloned();
|
||||
let setup_dir = if let Some(setup_dir) = args.get_one::<PathBuf>(SETUP_DIR) {
|
||||
setup_dir.clone()
|
||||
} else if let Some(target_exe) = args.get_one::<String>(TARGET_EXE) {
|
||||
@ -253,6 +255,7 @@ pub async fn build_local_context(
|
||||
task_id,
|
||||
instance_id,
|
||||
setup_dir,
|
||||
extra_dir,
|
||||
machine_identity: MachineIdentity {
|
||||
machine_id: Uuid::nil(),
|
||||
machine_name: "local".to_string(),
|
||||
|
@ -29,6 +29,7 @@ pub async fn run(args: &clap::ArgMatches, event_sender: Option<Sender<UiEvent>>)
|
||||
.get_one::<u64>(CHECK_RETRY_COUNT)
|
||||
.copied()
|
||||
.expect("has a default value");
|
||||
let extra_dir = context.common_config.extra_dir.as_deref();
|
||||
|
||||
let config = TestInputArgs {
|
||||
target_exe: target_exe.as_path(),
|
||||
@ -41,6 +42,7 @@ pub async fn run(args: &clap::ArgMatches, event_sender: Option<Sender<UiEvent>>)
|
||||
target_timeout,
|
||||
check_retry_count,
|
||||
setup_dir: &context.common_config.setup_dir,
|
||||
extra_dir,
|
||||
minimized_stack_depth: None,
|
||||
machine_identity: context.common_config.machine_identity,
|
||||
};
|
||||
|
@ -44,6 +44,7 @@ pub async fn run(args: &clap::ArgMatches, event_sender: Option<Sender<UiEvent>>)
|
||||
target_timeout,
|
||||
check_retry_count,
|
||||
setup_dir: &context.common_config.setup_dir,
|
||||
extra_dir: context.common_config.extra_dir.as_deref(),
|
||||
minimized_stack_depth: None,
|
||||
check_asan_log,
|
||||
check_debugger,
|
||||
|
@ -24,7 +24,8 @@ pub async fn run(args: &clap::ArgMatches) -> Result<()> {
|
||||
.get_one::<PathBuf>("setup_dir")
|
||||
.expect("marked as required");
|
||||
|
||||
let config = Config::from_file(config_path, setup_dir)?;
|
||||
let extra_dir = args.get_one::<PathBuf>("extra_dir").map(|f| f.as_path());
|
||||
let config = Config::from_file(config_path, setup_dir, extra_dir)?;
|
||||
|
||||
init_telemetry(config.common()).await;
|
||||
|
||||
@ -138,4 +139,9 @@ pub fn args(name: &'static str) -> Command {
|
||||
.required(true)
|
||||
.value_parser(value_parser!(PathBuf)),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("extra_dir")
|
||||
.required(false)
|
||||
.value_parser(value_parser!(PathBuf)),
|
||||
)
|
||||
}
|
||||
|
@ -209,6 +209,9 @@ pub async fn run_tool(
|
||||
.output_dir(&config.analysis.local_path)
|
||||
.tools_dir(&config.tools.local_path)
|
||||
.setup_dir(&config.common.setup_dir)
|
||||
.set_optional_ref(&config.common.extra_dir, |expand, extra_dir| {
|
||||
expand.extra_dir(extra_dir)
|
||||
})
|
||||
.job_id(&config.common.job_id)
|
||||
.task_id(&config.common.task_id)
|
||||
.set_optional_ref(&config.common.microsoft_telemetry_key, |tester, key| {
|
||||
|
@ -55,6 +55,9 @@ pub struct CommonConfig {
|
||||
#[serde(default)]
|
||||
pub setup_dir: PathBuf,
|
||||
|
||||
#[serde(default)]
|
||||
pub extra_dir: Option<PathBuf>,
|
||||
|
||||
/// Lower bound on available system memory. If the available memory drops
|
||||
/// below the limit, the task will exit with an error. This is a fail-fast
|
||||
/// mechanism to support debugging.
|
||||
@ -139,13 +142,15 @@ pub enum Config {
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn from_file(path: &Path, setup_dir: &Path) -> Result<Self> {
|
||||
pub fn from_file(path: &Path, setup_dir: &Path, extra_dir: Option<&Path>) -> Result<Self> {
|
||||
let json = std::fs::read_to_string(path)?;
|
||||
let json_config: serde_json::Value = serde_json::from_str(&json)?;
|
||||
|
||||
// override the setup_dir in the config file with the parameter value if specified
|
||||
let mut config: Self = serde_json::from_value(json_config)?;
|
||||
|
||||
config.common_mut().setup_dir = setup_dir.to_owned();
|
||||
config.common_mut().extra_dir = extra_dir.map(|x| x.to_owned());
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
|
@ -299,6 +299,9 @@ impl<'a> TaskContext<'a> {
|
||||
.input_path(input)
|
||||
.job_id(&self.config.common.job_id)
|
||||
.setup_dir(&self.config.common.setup_dir)
|
||||
.set_optional_ref(&self.config.common.extra_dir, |expand, extra_dir| {
|
||||
expand.extra_dir(extra_dir)
|
||||
})
|
||||
.target_exe(&target_exe)
|
||||
.target_options(&self.config.target_options)
|
||||
.task_id(&self.config.common.task_id);
|
||||
|
@ -299,6 +299,9 @@ impl<'a> TaskContext<'a> {
|
||||
.input_path(input)
|
||||
.job_id(&self.config.common.job_id)
|
||||
.setup_dir(&self.config.common.setup_dir)
|
||||
.set_optional_ref(&self.config.common.extra_dir, |expand, extra_dir| {
|
||||
expand.extra_dir(extra_dir)
|
||||
})
|
||||
.target_exe(&target_exe)
|
||||
.target_options(&self.config.target_options)
|
||||
.task_id(&self.config.common.task_id);
|
||||
|
@ -99,6 +99,7 @@ impl GeneratorTask {
|
||||
|
||||
let tester = Tester::new(
|
||||
&self.config.common.setup_dir,
|
||||
self.config.common.extra_dir.as_deref(),
|
||||
&target_exe,
|
||||
&self.config.target_options,
|
||||
&self.config.target_env,
|
||||
@ -168,6 +169,9 @@ impl GeneratorTask {
|
||||
.machine_id()
|
||||
.await?
|
||||
.setup_dir(&self.config.common.setup_dir)
|
||||
.set_optional_ref(&self.config.common.extra_dir, |expand, extra_dir| {
|
||||
expand.extra_dir(extra_dir)
|
||||
})
|
||||
.generated_inputs(&output_dir)
|
||||
.input_corpus(&corpus_dir)
|
||||
.generator_exe(&self.config.generator_exe)
|
||||
@ -298,6 +302,7 @@ mod tests {
|
||||
microsoft_telemetry_key: Default::default(),
|
||||
logs: Default::default(),
|
||||
setup_dir: Default::default(),
|
||||
extra_dir: Default::default(),
|
||||
min_available_memory_mb: Default::default(),
|
||||
machine_identity: onefuzz::machine_id::MachineIdentity {
|
||||
machine_id: uuid::Uuid::new_v4(),
|
||||
|
@ -86,6 +86,7 @@ impl common::LibFuzzerType for LibFuzzerDotnet {
|
||||
options,
|
||||
env,
|
||||
&config.common.setup_dir,
|
||||
config.common.extra_dir.as_ref(),
|
||||
config.common.machine_identity.clone(),
|
||||
))
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ impl common::LibFuzzerType for GenericLibFuzzer {
|
||||
config.target_options.clone(),
|
||||
config.target_env.clone(),
|
||||
&config.common.setup_dir,
|
||||
config.common.extra_dir.as_ref(),
|
||||
config.common.machine_identity.clone(),
|
||||
))
|
||||
}
|
||||
|
@ -214,6 +214,9 @@ async fn start_supervisor(
|
||||
.input_corpus(&inputs.local_path)
|
||||
.reports_dir(reports_dir)
|
||||
.setup_dir(&config.common.setup_dir)
|
||||
.set_optional_ref(&config.common.extra_dir, |expand, extra_dir| {
|
||||
expand.extra_dir(extra_dir)
|
||||
})
|
||||
.job_id(&config.common.job_id)
|
||||
.task_id(&config.common.task_id)
|
||||
.set_optional_ref(&config.tools, |expand, tools| {
|
||||
@ -391,6 +394,7 @@ mod tests {
|
||||
microsoft_telemetry_key: Default::default(),
|
||||
logs: Default::default(),
|
||||
setup_dir: Default::default(),
|
||||
extra_dir: Default::default(),
|
||||
min_available_memory_mb: Default::default(),
|
||||
machine_identity: MachineIdentity {
|
||||
machine_id: uuid::Uuid::new_v4(),
|
||||
|
@ -141,6 +141,9 @@ async fn merge(config: &Config, output_dir: impl AsRef<Path>) -> Result<()> {
|
||||
.generated_inputs(output_dir)
|
||||
.target_exe(&target_exe)
|
||||
.setup_dir(&config.common.setup_dir)
|
||||
.set_optional_ref(&config.common.extra_dir, |expand, extra_dir| {
|
||||
expand.extra_dir(extra_dir)
|
||||
})
|
||||
.tools_dir(&config.tools.local_path)
|
||||
.job_id(&config.common.job_id)
|
||||
.task_id(&config.common.task_id)
|
||||
|
@ -46,6 +46,7 @@ pub async fn spawn(config: Arc<Config>) -> Result<()> {
|
||||
config.target_options.clone(),
|
||||
config.target_env.clone(),
|
||||
&config.common.setup_dir,
|
||||
config.common.extra_dir.clone(),
|
||||
config.common.machine_identity.clone(),
|
||||
);
|
||||
fuzzer.verify(config.check_fuzzer_help, None).await?;
|
||||
@ -160,6 +161,7 @@ pub async fn merge_inputs(
|
||||
config.target_options.clone(),
|
||||
config.target_env.clone(),
|
||||
&config.common.setup_dir,
|
||||
config.common.extra_dir.clone(),
|
||||
config.common.machine_identity.clone(),
|
||||
);
|
||||
merger
|
||||
|
@ -60,6 +60,7 @@ impl RegressionHandler for GenericRegressionTask {
|
||||
try_resolve_setup_relative_path(&self.config.common.setup_dir, &self.config.target_exe)
|
||||
.await?;
|
||||
|
||||
let extra_dir = self.config.common.extra_dir.as_deref();
|
||||
let args = generic::TestInputArgs {
|
||||
input_url: Some(input_url),
|
||||
input: &input,
|
||||
@ -67,6 +68,7 @@ impl RegressionHandler for GenericRegressionTask {
|
||||
target_options: &self.config.target_options,
|
||||
target_env: &self.config.target_env,
|
||||
setup_dir: &self.config.common.setup_dir,
|
||||
extra_dir,
|
||||
task_id: self.config.common.task_id,
|
||||
job_id: self.config.common.job_id,
|
||||
target_timeout: self.config.target_timeout,
|
||||
|
@ -66,6 +66,7 @@ impl RegressionHandler for LibFuzzerRegressionTask {
|
||||
target_options: &self.config.target_options,
|
||||
target_env: &self.config.target_env,
|
||||
setup_dir: &self.config.common.setup_dir,
|
||||
extra_dir: self.config.common.extra_dir.as_deref(),
|
||||
task_id: self.config.common.task_id,
|
||||
job_id: self.config.common.job_id,
|
||||
target_timeout: self.config.target_timeout,
|
||||
|
@ -182,7 +182,10 @@ impl AsanProcessor {
|
||||
|
||||
let expand = Expand::new(&self.config.common.machine_identity)
|
||||
.input_path(input)
|
||||
.setup_dir(&self.config.common.setup_dir);
|
||||
.setup_dir(&self.config.common.setup_dir)
|
||||
.set_optional_ref(&self.config.common.extra_dir, |expand, extra_dir| {
|
||||
expand.extra_dir(extra_dir)
|
||||
});
|
||||
let expanded_args = expand.evaluate(&args)?;
|
||||
|
||||
let env = {
|
||||
|
@ -113,6 +113,7 @@ pub struct TestInputArgs<'a> {
|
||||
pub target_options: &'a [String],
|
||||
pub target_env: &'a HashMap<String, String>,
|
||||
pub setup_dir: &'a Path,
|
||||
pub extra_dir: Option<&'a Path>,
|
||||
pub task_id: Uuid,
|
||||
pub job_id: Uuid,
|
||||
pub target_timeout: Option<u64>,
|
||||
@ -124,8 +125,10 @@ pub struct TestInputArgs<'a> {
|
||||
}
|
||||
|
||||
pub async fn test_input(args: TestInputArgs<'_>) -> Result<CrashTestResult> {
|
||||
let extra_dir = args.extra_dir;
|
||||
let tester = Tester::new(
|
||||
args.setup_dir,
|
||||
extra_dir,
|
||||
args.target_exe,
|
||||
args.target_options,
|
||||
args.target_env,
|
||||
@ -201,6 +204,7 @@ impl<'a> GenericReportProcessor<'a> {
|
||||
try_resolve_setup_relative_path(&self.config.common.setup_dir, &self.config.target_exe)
|
||||
.await?;
|
||||
|
||||
let extra_dir = self.config.common.extra_dir.as_deref();
|
||||
let args = TestInputArgs {
|
||||
input_url,
|
||||
input,
|
||||
@ -208,6 +212,7 @@ impl<'a> GenericReportProcessor<'a> {
|
||||
target_options: &self.config.target_options,
|
||||
target_env: &self.config.target_env,
|
||||
setup_dir: &self.config.common.setup_dir,
|
||||
extra_dir,
|
||||
task_id: self.config.common.task_id,
|
||||
job_id: self.config.common.job_id,
|
||||
target_timeout: self.config.target_timeout,
|
||||
|
@ -76,6 +76,7 @@ impl ReportTask {
|
||||
self.config.target_options.clone(),
|
||||
self.config.target_env.clone(),
|
||||
&self.config.common.setup_dir,
|
||||
self.config.common.extra_dir.clone(),
|
||||
self.config.common.machine_identity.clone(),
|
||||
);
|
||||
fuzzer.verify(self.config.check_fuzzer_help, None).await
|
||||
@ -118,6 +119,7 @@ pub struct TestInputArgs<'a> {
|
||||
pub target_options: &'a [String],
|
||||
pub target_env: &'a HashMap<String, String>,
|
||||
pub setup_dir: &'a Path,
|
||||
pub extra_dir: Option<&'a Path>,
|
||||
pub task_id: uuid::Uuid,
|
||||
pub job_id: uuid::Uuid,
|
||||
pub target_timeout: Option<u64>,
|
||||
@ -132,6 +134,7 @@ pub async fn test_input(args: TestInputArgs<'_>) -> Result<CrashTestResult> {
|
||||
args.target_options.to_vec(),
|
||||
args.target_env.clone(),
|
||||
args.setup_dir,
|
||||
args.extra_dir.map(PathBuf::from),
|
||||
args.machine_identity,
|
||||
);
|
||||
|
||||
@ -215,6 +218,7 @@ impl AsanProcessor {
|
||||
target_options: &self.config.target_options,
|
||||
target_env: &self.config.target_env,
|
||||
setup_dir: &self.config.common.setup_dir,
|
||||
extra_dir: self.config.common.extra_dir.as_deref(),
|
||||
task_id: self.config.common.task_id,
|
||||
job_id: self.config.common.job_id,
|
||||
target_timeout: self.config.target_timeout,
|
||||
|
@ -55,6 +55,7 @@ async fn main() -> Result<()> {
|
||||
let env = Default::default();
|
||||
let tester = Tester::new(
|
||||
&setup_dir,
|
||||
None,
|
||||
&opt.exe,
|
||||
&target_options,
|
||||
&env,
|
||||
|
@ -41,6 +41,7 @@ pub enum PlaceHolder {
|
||||
SupervisorExe,
|
||||
SupervisorOptions,
|
||||
SetupDir,
|
||||
ExtraDir,
|
||||
ReportsDir,
|
||||
JobId,
|
||||
TaskId,
|
||||
@ -74,6 +75,7 @@ impl PlaceHolder {
|
||||
Self::SupervisorExe => "{supervisor_exe}",
|
||||
Self::SupervisorOptions => "{supervisor_options}",
|
||||
Self::SetupDir => "{setup_dir}",
|
||||
Self::ExtraDir => "{extra_dir}",
|
||||
Self::ReportsDir => "{reports_dir}",
|
||||
Self::JobId => "{job_id}",
|
||||
Self::TaskId => "{task_id}",
|
||||
@ -317,6 +319,12 @@ impl<'a> Expand<'a> {
|
||||
self.set_value(PlaceHolder::SetupDir, ExpandedValue::Path(path))
|
||||
}
|
||||
|
||||
pub fn extra_dir(self, arg: impl AsRef<Path>) -> Self {
|
||||
let arg = arg.as_ref();
|
||||
let path = String::from(arg.to_string_lossy());
|
||||
self.set_value(PlaceHolder::ExtraDir, ExpandedValue::Path(path))
|
||||
}
|
||||
|
||||
pub fn coverage_dir(self, arg: impl AsRef<Path>) -> Self {
|
||||
let arg = arg.as_ref();
|
||||
let path = String::from(arg.to_string_lossy());
|
||||
|
@ -27,6 +27,7 @@ const CRASH_SITE_UNAVAILABLE: &str = "<crash site unavailable>";
|
||||
|
||||
pub struct Tester<'a> {
|
||||
setup_dir: &'a Path,
|
||||
extra_dir: Option<&'a Path>,
|
||||
exe_path: &'a Path,
|
||||
arguments: &'a [String],
|
||||
environ: &'a HashMap<String, String>,
|
||||
@ -56,6 +57,7 @@ pub struct TestResult {
|
||||
impl<'a> Tester<'a> {
|
||||
pub fn new(
|
||||
setup_dir: &'a Path,
|
||||
extra_dir: Option<&'a Path>,
|
||||
exe_path: &'a Path,
|
||||
arguments: &'a [String],
|
||||
environ: &'a HashMap<String, String>,
|
||||
@ -63,6 +65,7 @@ impl<'a> Tester<'a> {
|
||||
) -> Self {
|
||||
Self {
|
||||
setup_dir,
|
||||
extra_dir,
|
||||
exe_path,
|
||||
arguments,
|
||||
environ,
|
||||
@ -298,7 +301,10 @@ impl<'a> Tester<'a> {
|
||||
.input_path(input_file)
|
||||
.target_exe(self.exe_path)
|
||||
.target_options(self.arguments)
|
||||
.setup_dir(self.setup_dir);
|
||||
.setup_dir(self.setup_dir)
|
||||
.set_optional(self.extra_dir.as_ref(), |expand, extra_dir| {
|
||||
expand.extra_dir(extra_dir)
|
||||
});
|
||||
|
||||
let argv = expand.evaluate(self.arguments)?;
|
||||
let mut env: HashMap<String, String> = HashMap::new();
|
||||
|
@ -37,6 +37,7 @@ pub struct LibFuzzerMergeOutput {
|
||||
|
||||
pub struct LibFuzzer {
|
||||
setup_dir: PathBuf,
|
||||
extra_dir: Option<PathBuf>,
|
||||
exe: PathBuf,
|
||||
options: Vec<String>,
|
||||
env: HashMap<String, String>,
|
||||
@ -49,6 +50,7 @@ impl LibFuzzer {
|
||||
options: Vec<String>,
|
||||
env: HashMap<String, String>,
|
||||
setup_dir: impl Into<PathBuf>,
|
||||
extra_dir: Option<impl Into<PathBuf>>,
|
||||
machine_identity: MachineIdentity,
|
||||
) -> Self {
|
||||
Self {
|
||||
@ -56,6 +58,7 @@ impl LibFuzzer {
|
||||
options,
|
||||
env,
|
||||
setup_dir: setup_dir.into(),
|
||||
extra_dir: extra_dir.map(|x| x.into()),
|
||||
machine_identity,
|
||||
}
|
||||
}
|
||||
@ -108,6 +111,9 @@ impl LibFuzzer {
|
||||
.target_exe(&self.exe)
|
||||
.target_options(&self.options)
|
||||
.setup_dir(&self.setup_dir)
|
||||
.set_optional(self.extra_dir.as_ref(), |expand, extra_dir| {
|
||||
expand.extra_dir(extra_dir)
|
||||
})
|
||||
.set_optional(corpus_dir, |e, corpus_dir| e.input_corpus(corpus_dir))
|
||||
.set_optional(fault_dir, |e, fault_dir| e.crashes(fault_dir));
|
||||
|
||||
@ -314,6 +320,7 @@ impl LibFuzzer {
|
||||
|
||||
let mut tester = Tester::new(
|
||||
&self.setup_dir,
|
||||
self.extra_dir.as_deref(),
|
||||
&self.exe,
|
||||
&options,
|
||||
&self.env,
|
||||
@ -443,6 +450,7 @@ mod tests {
|
||||
options.clone(),
|
||||
env.clone(),
|
||||
temp_setup_dir.path(),
|
||||
Option::<PathBuf>::None,
|
||||
MachineIdentity {
|
||||
machine_id: uuid::Uuid::new_v4(),
|
||||
machine_name: "test-input".into(),
|
||||
@ -476,6 +484,7 @@ mod tests {
|
||||
options.clone(),
|
||||
env.clone(),
|
||||
temp_setup_dir.path(),
|
||||
Option::<PathBuf>::None,
|
||||
MachineIdentity {
|
||||
machine_id: uuid::Uuid::new_v4(),
|
||||
machine_name: "test-input".into(),
|
||||
|
@ -53,6 +53,7 @@ class AFL(Command):
|
||||
notification_config: Optional[NotificationConfig] = None,
|
||||
debug: Optional[List[TaskDebugFlag]] = None,
|
||||
ensemble_sync_delay: Optional[int] = None,
|
||||
extra_container: Optional[Container] = None,
|
||||
) -> Optional[Job]:
|
||||
"""
|
||||
Basic AFL job
|
||||
@ -93,6 +94,7 @@ class AFL(Command):
|
||||
ContainerType.reports,
|
||||
ContainerType.unique_reports,
|
||||
)
|
||||
|
||||
if existing_inputs:
|
||||
self.onefuzz.containers.get(existing_inputs)
|
||||
helper.containers[ContainerType.inputs] = existing_inputs
|
||||
@ -133,6 +135,11 @@ class AFL(Command):
|
||||
(ContainerType.inputs, helper.containers[ContainerType.inputs]),
|
||||
]
|
||||
|
||||
if extra_container is not None:
|
||||
containers.append(
|
||||
(ContainerType.extra, helper.containers[ContainerType.extra])
|
||||
)
|
||||
|
||||
self.logger.info("creating afl fuzz task")
|
||||
fuzzer_task = self.onefuzz.tasks.create(
|
||||
helper.job.job_id,
|
||||
@ -166,6 +173,11 @@ class AFL(Command):
|
||||
),
|
||||
]
|
||||
|
||||
if extra_container is not None:
|
||||
report_containers.append(
|
||||
(ContainerType.extra, helper.containers[ContainerType.extra])
|
||||
)
|
||||
|
||||
self.logger.info("creating generic_crash_report task")
|
||||
self.onefuzz.tasks.create(
|
||||
helper.job.job_id,
|
||||
|
@ -74,6 +74,7 @@ class Libfuzzer(Command):
|
||||
analyzer_options: Optional[List[str]] = None,
|
||||
analyzer_env: Optional[Dict[str, str]] = None,
|
||||
tools: Optional[Container] = None,
|
||||
extra_container: Optional[Container] = None,
|
||||
) -> None:
|
||||
target_options = target_options or []
|
||||
|
||||
@ -331,6 +332,7 @@ class Libfuzzer(Command):
|
||||
analyzer_options: Optional[List[str]] = None,
|
||||
analyzer_env: Optional[Dict[str, str]] = None,
|
||||
tools: Optional[Container] = None,
|
||||
extra_container: Optional[Container] = None,
|
||||
) -> Optional[Job]:
|
||||
"""
|
||||
Basic libfuzzer job
|
||||
@ -413,9 +415,14 @@ class Libfuzzer(Command):
|
||||
else:
|
||||
source_allowlist_blob_name = None
|
||||
|
||||
containers = helper.containers
|
||||
|
||||
if extra_container is not None:
|
||||
containers[ContainerType.extra] = extra_container
|
||||
|
||||
self._create_tasks(
|
||||
job=helper.job,
|
||||
containers=helper.containers,
|
||||
containers=containers,
|
||||
pool_name=pool_name,
|
||||
target_exe=target_exe_blob_name,
|
||||
vm_count=vm_count,
|
||||
@ -474,6 +481,7 @@ class Libfuzzer(Command):
|
||||
debug: Optional[List[TaskDebugFlag]] = None,
|
||||
preserve_existing_outputs: bool = False,
|
||||
check_fuzzer_help: bool = True,
|
||||
extra_container: Optional[Container] = None,
|
||||
) -> Optional[Job]:
|
||||
"""
|
||||
libfuzzer merge task
|
||||
@ -510,6 +518,7 @@ class Libfuzzer(Command):
|
||||
helper.define_containers(
|
||||
ContainerType.setup,
|
||||
)
|
||||
|
||||
if inputs:
|
||||
helper.define_containers(ContainerType.inputs)
|
||||
|
||||
@ -535,6 +544,9 @@ class Libfuzzer(Command):
|
||||
),
|
||||
]
|
||||
|
||||
if extra_container is not None:
|
||||
merge_containers.append((ContainerType.extra, extra_container))
|
||||
|
||||
if inputs:
|
||||
merge_containers.append(
|
||||
(ContainerType.inputs, helper.containers[ContainerType.inputs])
|
||||
@ -598,6 +610,7 @@ class Libfuzzer(Command):
|
||||
colocate_secondary_tasks: bool = True,
|
||||
expect_crash_on_failure: bool = False,
|
||||
notification_config: Optional[NotificationConfig] = None,
|
||||
extra_container: Optional[Container] = None,
|
||||
) -> Optional[Job]:
|
||||
pool = self.onefuzz.pools.get(pool_name)
|
||||
|
||||
@ -673,6 +686,9 @@ class Libfuzzer(Command):
|
||||
(ContainerType.tools, fuzzer_tools_container),
|
||||
]
|
||||
|
||||
if extra_container is not None:
|
||||
fuzzer_containers.append((ContainerType.extra, extra_container))
|
||||
|
||||
helper.create_containers()
|
||||
helper.setup_notifications(notification_config)
|
||||
|
||||
@ -728,6 +744,9 @@ class Libfuzzer(Command):
|
||||
(ContainerType.tools, fuzzer_tools_container),
|
||||
]
|
||||
|
||||
if extra_container is not None:
|
||||
coverage_containers.append((ContainerType.extra, extra_container))
|
||||
|
||||
self.logger.info("creating `dotnet_coverage` task")
|
||||
self.onefuzz.tasks.create(
|
||||
helper.job.job_id,
|
||||
@ -756,6 +775,9 @@ class Libfuzzer(Command):
|
||||
(ContainerType.tools, fuzzer_tools_container),
|
||||
]
|
||||
|
||||
if extra_container is not None:
|
||||
report_containers.append((ContainerType.extra, extra_container))
|
||||
|
||||
self.logger.info("creating `dotnet_crash_report` task")
|
||||
self.onefuzz.tasks.create(
|
||||
helper.job.job_id,
|
||||
@ -808,6 +830,7 @@ class Libfuzzer(Command):
|
||||
crash_report_timeout: Optional[int] = 1,
|
||||
check_retry_count: Optional[int] = 300,
|
||||
check_fuzzer_help: bool = True,
|
||||
extra_container: Optional[Container] = None,
|
||||
) -> Optional[Job]:
|
||||
"""
|
||||
libfuzzer tasks, wrapped via qemu-user (PREVIEW FEATURE)
|
||||
@ -866,6 +889,9 @@ class Libfuzzer(Command):
|
||||
(ContainerType.inputs, helper.containers[ContainerType.inputs]),
|
||||
]
|
||||
|
||||
if extra_container is not None:
|
||||
fuzzer_containers.append((ContainerType.extra, extra_container))
|
||||
|
||||
helper.create_containers()
|
||||
|
||||
target_exe_blob_name = helper.setup_relative_blob_name(target_exe, None)
|
||||
@ -959,6 +985,9 @@ class Libfuzzer(Command):
|
||||
(ContainerType.no_repro, helper.containers[ContainerType.no_repro]),
|
||||
]
|
||||
|
||||
if extra_container is not None:
|
||||
report_containers.append((ContainerType.extra, extra_container))
|
||||
|
||||
self.logger.info("creating libfuzzer_crash_report task")
|
||||
self.onefuzz.tasks.create(
|
||||
helper.job.job_id,
|
||||
|
@ -11,7 +11,7 @@ from typing import Dict, List, Optional, Tuple
|
||||
|
||||
from onefuzztypes.enums import OS, ContainerType, TaskDebugFlag
|
||||
from onefuzztypes.models import NotificationConfig
|
||||
from onefuzztypes.primitives import File, PoolName
|
||||
from onefuzztypes.primitives import Container, File, PoolName
|
||||
|
||||
from onefuzz.api import Command
|
||||
from onefuzz.backend import container_file_path
|
||||
@ -119,6 +119,7 @@ class OssFuzz(Command):
|
||||
notification_config: Optional[NotificationConfig] = None,
|
||||
debug: Optional[List[TaskDebugFlag]] = None,
|
||||
ensemble_sync_delay: Optional[int] = None,
|
||||
extra_container: Optional[Container] = None,
|
||||
) -> None:
|
||||
"""
|
||||
OssFuzz style libfuzzer jobs
|
||||
@ -212,6 +213,10 @@ class OssFuzz(Command):
|
||||
ContainerType.no_repro,
|
||||
ContainerType.coverage,
|
||||
)
|
||||
|
||||
if extra_container is not None:
|
||||
helper.containers[ContainerType.extra] = extra_container
|
||||
|
||||
helper.create_containers()
|
||||
helper.setup_notifications(notification_config)
|
||||
|
||||
|
@ -50,6 +50,7 @@ class Radamsa(Command):
|
||||
debug: Optional[List[TaskDebugFlag]] = None,
|
||||
ensemble_sync_delay: Optional[int] = None,
|
||||
target_timeout: Optional[int] = None,
|
||||
extra_container: Optional[Container] = None,
|
||||
) -> Optional[Job]:
|
||||
"""
|
||||
Basic radamsa job
|
||||
@ -90,6 +91,7 @@ class Radamsa(Command):
|
||||
ContainerType.no_repro,
|
||||
ContainerType.analysis,
|
||||
)
|
||||
|
||||
if existing_inputs:
|
||||
self.onefuzz.containers.get(existing_inputs)
|
||||
helper.containers[ContainerType.readonly_inputs] = existing_inputs
|
||||
@ -155,6 +157,9 @@ class Radamsa(Command):
|
||||
),
|
||||
]
|
||||
|
||||
if extra_container is not None:
|
||||
containers.append((ContainerType.extra, extra_container))
|
||||
|
||||
fuzzer_task = self.onefuzz.tasks.create(
|
||||
helper.job.job_id,
|
||||
TaskType.generic_generator,
|
||||
@ -188,6 +193,9 @@ class Radamsa(Command):
|
||||
(ContainerType.no_repro, helper.containers[ContainerType.no_repro]),
|
||||
]
|
||||
|
||||
if extra_container is not None:
|
||||
report_containers.append((ContainerType.extra, extra_container))
|
||||
|
||||
self.logger.info("creating generic_crash_report task")
|
||||
self.onefuzz.tasks.create(
|
||||
helper.job.job_id,
|
||||
@ -231,6 +239,9 @@ class Radamsa(Command):
|
||||
(ContainerType.crashes, helper.containers[ContainerType.crashes]),
|
||||
]
|
||||
|
||||
if extra_container is not None:
|
||||
analysis_containers.append((ContainerType.extra, extra_container))
|
||||
|
||||
self.onefuzz.tasks.create(
|
||||
helper.job.job_id,
|
||||
TaskType.generic_analysis,
|
||||
|
@ -56,6 +56,7 @@ class Regression(Command):
|
||||
check_fuzzer_help: bool = True,
|
||||
delete_input_container: bool = True,
|
||||
check_regressions: bool = False,
|
||||
extra_container: Optional[Container] = None,
|
||||
) -> None:
|
||||
"""
|
||||
generic regression task
|
||||
@ -89,6 +90,7 @@ class Regression(Command):
|
||||
check_fuzzer_help=check_fuzzer_help,
|
||||
delete_input_container=delete_input_container,
|
||||
check_regressions=check_regressions,
|
||||
extra_container=extra_container,
|
||||
)
|
||||
|
||||
def libfuzzer(
|
||||
@ -115,6 +117,7 @@ class Regression(Command):
|
||||
check_fuzzer_help: bool = True,
|
||||
delete_input_container: bool = True,
|
||||
check_regressions: bool = False,
|
||||
extra_container: Optional[Container] = None,
|
||||
) -> None:
|
||||
"""
|
||||
libfuzzer regression task
|
||||
@ -148,6 +151,7 @@ class Regression(Command):
|
||||
check_fuzzer_help=check_fuzzer_help,
|
||||
delete_input_container=delete_input_container,
|
||||
check_regressions=check_regressions,
|
||||
extra_container=extra_container,
|
||||
)
|
||||
|
||||
def _create_job(
|
||||
@ -175,6 +179,7 @@ class Regression(Command):
|
||||
check_fuzzer_help: bool = True,
|
||||
delete_input_container: bool = True,
|
||||
check_regressions: bool = False,
|
||||
extra_container: Optional[Container] = None,
|
||||
) -> None:
|
||||
if dryrun:
|
||||
return None
|
||||
@ -216,6 +221,9 @@ class Regression(Command):
|
||||
),
|
||||
]
|
||||
|
||||
if extra_container:
|
||||
containers.append((ContainerType.extra, extra_container))
|
||||
|
||||
if crashes:
|
||||
helper.containers[
|
||||
ContainerType.readonly_inputs
|
||||
|
@ -109,6 +109,7 @@ TARGETS: Dict[str, Integration] = {
|
||||
},
|
||||
reboot_after_setup=True,
|
||||
inject_fake_regression=True,
|
||||
fuzzing_target_options=["--test:{extra}"],
|
||||
),
|
||||
"linux-libfuzzer-with-options": Integration(
|
||||
template=TemplateType.libfuzzer,
|
||||
@ -180,6 +181,7 @@ TARGETS: Dict[str, Integration] = {
|
||||
os=OS.linux,
|
||||
target_exe="fuzz_target_1",
|
||||
wait_for_files={ContainerType.unique_reports: 1, ContainerType.coverage: 1},
|
||||
fuzzing_target_options=["--test:{extra}"],
|
||||
),
|
||||
"linux-trivial-crash": Integration(
|
||||
template=TemplateType.radamsa,
|
||||
@ -209,6 +211,7 @@ TARGETS: Dict[str, Integration] = {
|
||||
ContainerType.coverage: 1,
|
||||
},
|
||||
inject_fake_regression=True,
|
||||
fuzzing_target_options=["--test:{extra}"],
|
||||
),
|
||||
"windows-libfuzzer-linked-library": Integration(
|
||||
template=TemplateType.libfuzzer,
|
||||
@ -575,6 +578,8 @@ class TestOnefuzz:
|
||||
|
||||
job: Optional[Job] = None
|
||||
if config.template == TemplateType.libfuzzer:
|
||||
# building the extra container to test this variable substitution
|
||||
extra = self.of.containers.create("extra")
|
||||
job = self.of.template.libfuzzer.basic(
|
||||
self.project,
|
||||
target,
|
||||
@ -588,6 +593,7 @@ class TestOnefuzz:
|
||||
reboot_after_setup=config.reboot_after_setup or False,
|
||||
target_options=config.target_options,
|
||||
fuzzing_target_options=config.fuzzing_target_options,
|
||||
extra_container=Container(extra.name),
|
||||
)
|
||||
elif config.template == TemplateType.libfuzzer_dotnet:
|
||||
if setup is None:
|
||||
|
@ -228,6 +228,7 @@ class ContainerType(Enum):
|
||||
unique_reports = "unique_reports"
|
||||
regression_reports = "regression_reports"
|
||||
logs = "logs"
|
||||
extra = "extra"
|
||||
|
||||
@classmethod
|
||||
def reset_defaults(cls) -> List["ContainerType"]:
|
||||
|
@ -408,6 +408,7 @@ class TaskUnitConfig(BaseModel):
|
||||
unique_inputs: CONTAINER_DEF
|
||||
unique_reports: CONTAINER_DEF
|
||||
regression_reports: CONTAINER_DEF
|
||||
extra: CONTAINER_DEF
|
||||
|
||||
|
||||
class Forward(BaseModel):
|
||||
|
Reference in New Issue
Block a user