Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions docs/webhook_events.md
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,11 @@ If webhook is set to have Event Grid message format then the payload will look a
"title": "Generator Options",
"type": "array"
},
"min_available_memory_mb": {
"minimum": 0,
"title": "Min Available Memory Mb",
"type": "integer"
},
"minimized_stack_depth": {
"title": "Minimized Stack Depth",
"type": "integer"
Expand Down Expand Up @@ -2332,6 +2337,11 @@ If webhook is set to have Event Grid message format then the payload will look a
"title": "Generator Options",
"type": "array"
},
"min_available_memory_mb": {
"minimum": 0,
"title": "Min Available Memory Mb",
"type": "integer"
},
"minimized_stack_depth": {
"title": "Minimized Stack Depth",
"type": "integer"
Expand Down Expand Up @@ -3054,6 +3064,11 @@ If webhook is set to have Event Grid message format then the payload will look a
"title": "Generator Options",
"type": "array"
},
"min_available_memory_mb": {
"minimum": 0,
"title": "Min Available Memory Mb",
"type": "integer"
},
"minimized_stack_depth": {
"title": "Minimized Stack Depth",
"type": "integer"
Expand Down Expand Up @@ -3572,6 +3587,11 @@ If webhook is set to have Event Grid message format then the payload will look a
"title": "Generator Options",
"type": "array"
},
"min_available_memory_mb": {
"minimum": 0,
"title": "Min Available Memory Mb",
"type": "integer"
},
"minimized_stack_depth": {
"title": "Minimized Stack Depth",
"type": "integer"
Expand Down Expand Up @@ -4056,6 +4076,11 @@ If webhook is set to have Event Grid message format then the payload will look a
"title": "Generator Options",
"type": "array"
},
"min_available_memory_mb": {
"minimum": 0,
"title": "Min Available Memory Mb",
"type": "integer"
},
"minimized_stack_depth": {
"title": "Minimized Stack Depth",
"type": "integer"
Expand Down Expand Up @@ -4514,6 +4539,11 @@ If webhook is set to have Event Grid message format then the payload will look a
"title": "Generator Options",
"type": "array"
},
"min_available_memory_mb": {
"minimum": 0,
"title": "Min Available Memory Mb",
"type": "integer"
},
"minimized_stack_depth": {
"title": "Minimized Stack Depth",
"type": "integer"
Expand Down Expand Up @@ -4999,6 +5029,11 @@ If webhook is set to have Event Grid message format then the payload will look a
"title": "Generator Options",
"type": "array"
},
"min_available_memory_mb": {
"minimum": 0,
"title": "Min Available Memory Mb",
"type": "integer"
},
"minimized_stack_depth": {
"title": "Minimized Stack Depth",
"type": "integer"
Expand Down Expand Up @@ -6743,6 +6778,11 @@ If webhook is set to have Event Grid message format then the payload will look a
"title": "Generator Options",
"type": "array"
},
"min_available_memory_mb": {
"minimum": 0,
"title": "Min Available Memory Mb",
"type": "integer"
},
"minimized_stack_depth": {
"title": "Minimized Stack Depth",
"type": "integer"
Expand Down
2 changes: 2 additions & 0 deletions src/ApiService/ApiService/OneFuzzTypes/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ public record TaskDetails(
List<string>? ReportList = null,
long? MinimizedStackDepth = null,
Dictionary<string, string>? TaskEnv = null,
ulong? MinAvailableMemoryMb = null,

// Deprecated. Retained for processing old table data.
string? CoverageFilter = null,
Expand Down Expand Up @@ -1164,6 +1165,7 @@ Dictionary<string, string> Tags
public IContainerDef? RegressionReports { get; set; }
public IContainerDef? ExtraSetup { get; set; }
public IContainerDef? ExtraOutput { get; set; }
public ulong? MinAvailableMemoryMb { get; set; }
}

public record NodeCommandEnvelope(
Expand Down
5 changes: 4 additions & 1 deletion src/ApiService/ApiService/onefuzzlib/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ private static BlobContainerSasPermissions ConvertPermissions(ContainerPermissio
HeartbeatQueue: await _queue.GetQueueSas("task-heartbeat", StorageType.Config, QueueSasPermissions.Add) ?? throw new Exception("unable to get heartbeat queue sas"),
JobResultQueue: await _queue.GetQueueSas("job-result", StorageType.Config, QueueSasPermissions.Add) ?? throw new Exception("unable to get heartbeat queue sas"),
Tags: task.Config.Tags ?? new Dictionary<string, string>()
);
) {
// It's okay if this is null because the agent will use a default value if so.
MinAvailableMemoryMb = task.Config.Task.MinAvailableMemoryMb,
};

if (definition.MonitorQueue != null) {
config.inputQueue = await _queue.GetQueueSas(task.TaskId.ToString(), StorageType.Corpus, QueueSasPermissions.All);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ public static async Async.Task<TemplateValidationResponse> ValidateScribanTempla
targetOptions,
1,
new Dictionary<string, string>(),
null,
"coverage filter",
"module allow list",
"source allow list",
Expand Down
44 changes: 25 additions & 19 deletions src/agent/onefuzz-task/src/managed/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT License.
use std::path::PathBuf;

use anyhow::{bail, Result};
use anyhow::Result;
use clap::{value_parser, Arg, Command};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};

Expand Down Expand Up @@ -96,21 +96,29 @@ pub async fn run(args: &clap::ArgMatches) -> Result<()> {

let min_available_memory_bytes = 1_000_000 * config.common().min_available_memory_mb;

// If the memory limit is 0, this will resolve immediately with an error.
let check_oom = out_of_memory(min_available_memory_bytes);

let result = tokio::select! {
result = config.run() => result,

// Ignore this task if it returns due to a querying error.
Ok(oom) = check_oom => {
// Convert the OOM notification to an error, so we can log it below.
let err = anyhow::format_err!("out of memory: {} bytes available, {} required", oom.available_bytes, oom.min_bytes);
Err(err)
},

_shutdown = shutdown_listener => {
Ok(())
let result = match min_available_memory_bytes {
0 => {
log::info!("memory watchdog is disabled: this task may fail suddenly if it runs out of memory.");
config.run().await
}
_ => {
// If the memory limit is 0, this will never return.
let check_oom = out_of_memory(min_available_memory_bytes);

tokio::select! {
result = config.run() => result,

// Ignore this task if it returns due to a querying error.
Ok(oom) = check_oom => {
// Convert the OOM notification to an error, so we can log it below.
let err = anyhow::format_err!("out of memory: {} bytes available, {} required", oom.available_bytes, oom.min_bytes);
Err(err)
},

_shutdown = shutdown_listener => {
Ok(())
}
}
}
};

Expand All @@ -131,9 +139,7 @@ const MAX_OOM_QUERY_ERRORS: usize = 5;
//
// Parameterized to enable future configuration by VMSS.
async fn out_of_memory(min_bytes: u64) -> Result<OutOfMemory> {
if min_bytes == 0 {
bail!("available memory minimum is unreachable");
}
log::info!("memory watchdog is enabled: this task will fail informatively if there are {} bytes ({:.2}MB) or fewer of usable memory left.", min_bytes, min_bytes as f64 / 1_000_000f64);

let mut consecutive_query_errors = 0;

Expand Down
2 changes: 2 additions & 0 deletions src/cli/onefuzz/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1061,6 +1061,7 @@ def create(
module_allowlist: Optional[str] = None,
source_allowlist: Optional[str] = None,
task_env: Optional[Dict[str, str]] = None,
min_available_memory_mb: Optional[int] = None,
) -> models.Task:
"""
Create a task
Expand Down Expand Up @@ -1138,6 +1139,7 @@ def create(
module_allowlist=module_allowlist,
source_allowlist=source_allowlist,
task_env=task_env,
min_available_memory_mb=min_available_memory_mb,
),
)

Expand Down
2 changes: 2 additions & 0 deletions src/cli/onefuzz/templates/afl.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ def basic(
debug: Optional[List[TaskDebugFlag]] = None,
ensemble_sync_delay: Optional[int] = None,
extra_setup_container: Optional[Container] = None,
min_available_memory_mb: Optional[int] = None,
) -> Optional[Job]:
"""
Basic AFL job
Expand Down Expand Up @@ -166,6 +167,7 @@ def basic(
target_env=target_env,
debug=debug,
ensemble_sync_delay=ensemble_sync_delay,
min_available_memory_mb=min_available_memory_mb,
)

report_containers = [
Expand Down
17 changes: 17 additions & 0 deletions src/cli/onefuzz/templates/libfuzzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ def _create_tasks(
analyzer_env: Optional[Dict[str, str]] = None,
tools: Optional[Container] = None,
task_env: Optional[Dict[str, str]] = None,
min_available_memory_mb: Optional[int] = None,
) -> None:
target_options = target_options or []
regression_containers: List[Tuple[ContainerType, Container]] = [
Expand Down Expand Up @@ -127,6 +128,7 @@ def _create_tasks(
colocate=colocate_all_tasks or colocate_secondary_tasks,
minimized_stack_depth=minimized_stack_depth,
task_env=task_env,
min_available_memory_mb=min_available_memory_mb,
)

fuzzer_containers: List[Tuple[ContainerType, Container]] = [
Expand Down Expand Up @@ -180,6 +182,7 @@ def _create_tasks(
check_fuzzer_help=check_fuzzer_help,
expect_crash_on_failure=expect_crash_on_failure,
task_env=task_env,
min_available_memory_mb=min_available_memory_mb,
)

prereq_tasks = [fuzzer_task.task_id, regression_task.task_id]
Expand Down Expand Up @@ -243,6 +246,7 @@ def _create_tasks(
module_allowlist=module_allowlist,
source_allowlist=source_allowlist,
task_env=task_env,
min_available_memory_mb=min_available_memory_mb,
)

report_containers: List[Tuple[ContainerType, Container]] = [
Expand Down Expand Up @@ -280,6 +284,7 @@ def _create_tasks(
colocate=colocate_all_tasks or colocate_secondary_tasks,
minimized_stack_depth=minimized_stack_depth,
task_env=task_env,
min_available_memory_mb=min_available_memory_mb,
)

if analyzer_exe is not None:
Expand Down Expand Up @@ -320,6 +325,7 @@ def _create_tasks(
debug=debug,
target_timeout=target_timeout,
task_env=task_env,
min_available_memory_mb=min_available_memory_mb,
)

def basic(
Expand Down Expand Up @@ -369,6 +375,7 @@ def basic(
extra_output_container: Optional[Container] = None,
crashes: Optional[Container] = None,
task_env: Optional[Dict[str, str]] = None,
min_available_memory_mb: Optional[int] = None,
) -> Optional[Job]:
"""
Basic libfuzzer job
Expand Down Expand Up @@ -507,6 +514,7 @@ def basic(
tools=tools,
task_env=task_env,
target_timeout=target_timeout,
min_available_memory_mb=min_available_memory_mb,
)

self.logger.info("done creating tasks")
Expand Down Expand Up @@ -543,6 +551,7 @@ def merge(
no_check_fuzzer_help: bool = False,
extra_setup_container: Optional[Container] = None,
task_env: Optional[Dict[str, str]] = None,
min_available_memory_mb: Optional[int] = None,
) -> Optional[Job]:
"""
libfuzzer merge task
Expand Down Expand Up @@ -657,6 +666,7 @@ def merge(
preserve_existing_outputs=preserve_existing_outputs,
check_fuzzer_help=check_fuzzer_help,
task_env=task_env,
min_available_memory_mb=min_available_memory_mb,
)

self.logger.info("done creating tasks")
Expand Down Expand Up @@ -698,6 +708,7 @@ def dotnet(
extra_setup_container: Optional[Container] = None,
crashes: Optional[Container] = None,
task_env: Optional[Dict[str, str]] = None,
min_available_memory_mb: Optional[int] = None,
) -> Optional[Job]:
pool = self.onefuzz.pools.get(pool_name)

Expand Down Expand Up @@ -820,6 +831,7 @@ def dotnet(
expect_crash_on_failure=expect_crash_on_failure,
check_fuzzer_help=False,
task_env=task_env,
min_available_memory_mb=min_available_memory_mb,
)

# Ensure the fuzzing task starts before we schedule the coverage and
Expand Down Expand Up @@ -874,6 +886,7 @@ def dotnet(
debug=debug,
colocate=colocate_all_tasks or colocate_secondary_tasks,
task_env=task_env,
min_available_memory_mb=min_available_memory_mb,
)

report_containers = [
Expand Down Expand Up @@ -915,6 +928,7 @@ def dotnet(
debug=debug,
colocate=colocate_all_tasks or colocate_secondary_tasks,
task_env=task_env,
min_available_memory_mb=min_available_memory_mb,
)

self.logger.info("done creating tasks")
Expand Down Expand Up @@ -956,6 +970,7 @@ def qemu_user(
crashes: Optional[Container] = None,
readonly_inputs: Optional[Container] = None,
task_env: Optional[Dict[str, str]] = None,
min_available_memory_mb: Optional[int] = None,
) -> Optional[Job]:
"""
libfuzzer tasks, wrapped via qemu-user (PREVIEW FEATURE)
Expand Down Expand Up @@ -1125,6 +1140,7 @@ def qemu_user(
expect_crash_on_failure=False,
check_fuzzer_help=check_fuzzer_help,
task_env=task_env,
min_available_memory_mb=min_available_memory_mb,
)

report_containers = [
Expand Down Expand Up @@ -1167,6 +1183,7 @@ def qemu_user(
expect_crash_on_failure=False,
check_fuzzer_help=check_fuzzer_help,
task_env=task_env,
min_available_memory_mb=min_available_memory_mb,
)

self.logger.info("done creating tasks")
Expand Down
2 changes: 2 additions & 0 deletions src/cli/onefuzz/templates/ossfuzz.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ def libfuzzer(
debug: Optional[List[TaskDebugFlag]] = None,
ensemble_sync_delay: Optional[int] = None,
extra_setup_container: Optional[Container] = None,
min_available_memory_mb: Optional[int] = None,
) -> None:
"""
OssFuzz style libfuzzer jobs
Expand Down Expand Up @@ -257,6 +258,7 @@ def libfuzzer(
tags=helper.tags,
debug=debug,
ensemble_sync_delay=ensemble_sync_delay,
min_available_memory_mb=min_available_memory_mb,
)
helpers.append(helper)
base_helper.wait()
Loading