Skip to content

Commit 97d102e

Browse files
Merge pull request #466 from microsoft/main
Fork Sync: Update from parent repository
2 parents 0ff4868 + d9ac2a7 commit 97d102e

File tree

12 files changed

+107
-21
lines changed

12 files changed

+107
-21
lines changed

docs/webhook_events.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,11 @@ If webhook is set to have Event Grid message format then the payload will look a
445445
"title": "Generator Options",
446446
"type": "array"
447447
},
448+
"min_available_memory_mb": {
449+
"minimum": 0,
450+
"title": "Min Available Memory Mb",
451+
"type": "integer"
452+
},
448453
"minimized_stack_depth": {
449454
"title": "Minimized Stack Depth",
450455
"type": "integer"
@@ -2332,6 +2337,11 @@ If webhook is set to have Event Grid message format then the payload will look a
23322337
"title": "Generator Options",
23332338
"type": "array"
23342339
},
2340+
"min_available_memory_mb": {
2341+
"minimum": 0,
2342+
"title": "Min Available Memory Mb",
2343+
"type": "integer"
2344+
},
23352345
"minimized_stack_depth": {
23362346
"title": "Minimized Stack Depth",
23372347
"type": "integer"
@@ -3054,6 +3064,11 @@ If webhook is set to have Event Grid message format then the payload will look a
30543064
"title": "Generator Options",
30553065
"type": "array"
30563066
},
3067+
"min_available_memory_mb": {
3068+
"minimum": 0,
3069+
"title": "Min Available Memory Mb",
3070+
"type": "integer"
3071+
},
30573072
"minimized_stack_depth": {
30583073
"title": "Minimized Stack Depth",
30593074
"type": "integer"
@@ -3572,6 +3587,11 @@ If webhook is set to have Event Grid message format then the payload will look a
35723587
"title": "Generator Options",
35733588
"type": "array"
35743589
},
3590+
"min_available_memory_mb": {
3591+
"minimum": 0,
3592+
"title": "Min Available Memory Mb",
3593+
"type": "integer"
3594+
},
35753595
"minimized_stack_depth": {
35763596
"title": "Minimized Stack Depth",
35773597
"type": "integer"
@@ -4056,6 +4076,11 @@ If webhook is set to have Event Grid message format then the payload will look a
40564076
"title": "Generator Options",
40574077
"type": "array"
40584078
},
4079+
"min_available_memory_mb": {
4080+
"minimum": 0,
4081+
"title": "Min Available Memory Mb",
4082+
"type": "integer"
4083+
},
40594084
"minimized_stack_depth": {
40604085
"title": "Minimized Stack Depth",
40614086
"type": "integer"
@@ -4514,6 +4539,11 @@ If webhook is set to have Event Grid message format then the payload will look a
45144539
"title": "Generator Options",
45154540
"type": "array"
45164541
},
4542+
"min_available_memory_mb": {
4543+
"minimum": 0,
4544+
"title": "Min Available Memory Mb",
4545+
"type": "integer"
4546+
},
45174547
"minimized_stack_depth": {
45184548
"title": "Minimized Stack Depth",
45194549
"type": "integer"
@@ -4999,6 +5029,11 @@ If webhook is set to have Event Grid message format then the payload will look a
49995029
"title": "Generator Options",
50005030
"type": "array"
50015031
},
5032+
"min_available_memory_mb": {
5033+
"minimum": 0,
5034+
"title": "Min Available Memory Mb",
5035+
"type": "integer"
5036+
},
50025037
"minimized_stack_depth": {
50035038
"title": "Minimized Stack Depth",
50045039
"type": "integer"
@@ -6743,6 +6778,11 @@ If webhook is set to have Event Grid message format then the payload will look a
67436778
"title": "Generator Options",
67446779
"type": "array"
67456780
},
6781+
"min_available_memory_mb": {
6782+
"minimum": 0,
6783+
"title": "Min Available Memory Mb",
6784+
"type": "integer"
6785+
},
67466786
"minimized_stack_depth": {
67476787
"title": "Minimized Stack Depth",
67486788
"type": "integer"

src/ApiService/ApiService/OneFuzzTypes/Model.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ public record TaskDetails(
239239
List<string>? ReportList = null,
240240
long? MinimizedStackDepth = null,
241241
Dictionary<string, string>? TaskEnv = null,
242+
ulong? MinAvailableMemoryMb = null,
242243

243244
// Deprecated. Retained for processing old table data.
244245
string? CoverageFilter = null,
@@ -1164,6 +1165,7 @@ Dictionary<string, string> Tags
11641165
public IContainerDef? RegressionReports { get; set; }
11651166
public IContainerDef? ExtraSetup { get; set; }
11661167
public IContainerDef? ExtraOutput { get; set; }
1168+
public ulong? MinAvailableMemoryMb { get; set; }
11671169
}
11681170

11691171
public record NodeCommandEnvelope(

src/ApiService/ApiService/onefuzzlib/Config.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,10 @@ private static BlobContainerSasPermissions ConvertPermissions(ContainerPermissio
7373
HeartbeatQueue: await _queue.GetQueueSas("task-heartbeat", StorageType.Config, QueueSasPermissions.Add) ?? throw new Exception("unable to get heartbeat queue sas"),
7474
JobResultQueue: await _queue.GetQueueSas("job-result", StorageType.Config, QueueSasPermissions.Add) ?? throw new Exception("unable to get heartbeat queue sas"),
7575
Tags: task.Config.Tags ?? new Dictionary<string, string>()
76-
);
76+
) {
77+
// It's okay if this is null because the agent will use a default value if so.
78+
MinAvailableMemoryMb = task.Config.Task.MinAvailableMemoryMb,
79+
};
7780

7881
if (definition.MonitorQueue != null) {
7982
config.inputQueue = await _queue.GetQueueSas(task.TaskId.ToString(), StorageType.Corpus, QueueSasPermissions.All);

src/ApiService/ApiService/onefuzzlib/notifications/JinjaTemplateAdapter.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ public static async Async.Task<TemplateValidationResponse> ValidateScribanTempla
166166
targetOptions,
167167
1,
168168
new Dictionary<string, string>(),
169+
null,
169170
"coverage filter",
170171
"module allow list",
171172
"source allow list",

src/agent/onefuzz-task/src/managed/cmd.rs

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Licensed under the MIT License.
33
use std::path::PathBuf;
44

5-
use anyhow::{bail, Result};
5+
use anyhow::Result;
66
use clap::{value_parser, Arg, Command};
77
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
88

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

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

99-
// If the memory limit is 0, this will resolve immediately with an error.
100-
let check_oom = out_of_memory(min_available_memory_bytes);
101-
102-
let result = tokio::select! {
103-
result = config.run() => result,
104-
105-
// Ignore this task if it returns due to a querying error.
106-
Ok(oom) = check_oom => {
107-
// Convert the OOM notification to an error, so we can log it below.
108-
let err = anyhow::format_err!("out of memory: {} bytes available, {} required", oom.available_bytes, oom.min_bytes);
109-
Err(err)
110-
},
111-
112-
_shutdown = shutdown_listener => {
113-
Ok(())
99+
let result = match min_available_memory_bytes {
100+
0 => {
101+
log::info!("memory watchdog is disabled: this task may fail suddenly if it runs out of memory.");
102+
config.run().await
103+
}
104+
_ => {
105+
// If the memory limit is 0, this will never return.
106+
let check_oom = out_of_memory(min_available_memory_bytes);
107+
108+
tokio::select! {
109+
result = config.run() => result,
110+
111+
// Ignore this task if it returns due to a querying error.
112+
Ok(oom) = check_oom => {
113+
// Convert the OOM notification to an error, so we can log it below.
114+
let err = anyhow::format_err!("out of memory: {} bytes available, {} required", oom.available_bytes, oom.min_bytes);
115+
Err(err)
116+
},
117+
118+
_shutdown = shutdown_listener => {
119+
Ok(())
120+
}
121+
}
114122
}
115123
};
116124

@@ -131,9 +139,7 @@ const MAX_OOM_QUERY_ERRORS: usize = 5;
131139
//
132140
// Parameterized to enable future configuration by VMSS.
133141
async fn out_of_memory(min_bytes: u64) -> Result<OutOfMemory> {
134-
if min_bytes == 0 {
135-
bail!("available memory minimum is unreachable");
136-
}
142+
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);
137143

138144
let mut consecutive_query_errors = 0;
139145

src/cli/onefuzz/api.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,7 @@ def create(
10611061
module_allowlist: Optional[str] = None,
10621062
source_allowlist: Optional[str] = None,
10631063
task_env: Optional[Dict[str, str]] = None,
1064+
min_available_memory_mb: Optional[int] = None,
10641065
) -> models.Task:
10651066
"""
10661067
Create a task
@@ -1138,6 +1139,7 @@ def create(
11381139
module_allowlist=module_allowlist,
11391140
source_allowlist=source_allowlist,
11401141
task_env=task_env,
1142+
min_available_memory_mb=min_available_memory_mb,
11411143
),
11421144
)
11431145

src/cli/onefuzz/templates/afl.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ def basic(
5555
debug: Optional[List[TaskDebugFlag]] = None,
5656
ensemble_sync_delay: Optional[int] = None,
5757
extra_setup_container: Optional[Container] = None,
58+
min_available_memory_mb: Optional[int] = None,
5859
) -> Optional[Job]:
5960
"""
6061
Basic AFL job
@@ -166,6 +167,7 @@ def basic(
166167
target_env=target_env,
167168
debug=debug,
168169
ensemble_sync_delay=ensemble_sync_delay,
170+
min_available_memory_mb=min_available_memory_mb,
169171
)
170172

171173
report_containers = [

src/cli/onefuzz/templates/libfuzzer.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ def _create_tasks(
8383
analyzer_env: Optional[Dict[str, str]] = None,
8484
tools: Optional[Container] = None,
8585
task_env: Optional[Dict[str, str]] = None,
86+
min_available_memory_mb: Optional[int] = None,
8687
) -> None:
8788
target_options = target_options or []
8889
regression_containers: List[Tuple[ContainerType, Container]] = [
@@ -127,6 +128,7 @@ def _create_tasks(
127128
colocate=colocate_all_tasks or colocate_secondary_tasks,
128129
minimized_stack_depth=minimized_stack_depth,
129130
task_env=task_env,
131+
min_available_memory_mb=min_available_memory_mb,
130132
)
131133

132134
fuzzer_containers: List[Tuple[ContainerType, Container]] = [
@@ -180,6 +182,7 @@ def _create_tasks(
180182
check_fuzzer_help=check_fuzzer_help,
181183
expect_crash_on_failure=expect_crash_on_failure,
182184
task_env=task_env,
185+
min_available_memory_mb=min_available_memory_mb,
183186
)
184187

185188
prereq_tasks = [fuzzer_task.task_id, regression_task.task_id]
@@ -243,6 +246,7 @@ def _create_tasks(
243246
module_allowlist=module_allowlist,
244247
source_allowlist=source_allowlist,
245248
task_env=task_env,
249+
min_available_memory_mb=min_available_memory_mb,
246250
)
247251

248252
report_containers: List[Tuple[ContainerType, Container]] = [
@@ -280,6 +284,7 @@ def _create_tasks(
280284
colocate=colocate_all_tasks or colocate_secondary_tasks,
281285
minimized_stack_depth=minimized_stack_depth,
282286
task_env=task_env,
287+
min_available_memory_mb=min_available_memory_mb,
283288
)
284289

285290
if analyzer_exe is not None:
@@ -320,6 +325,7 @@ def _create_tasks(
320325
debug=debug,
321326
target_timeout=target_timeout,
322327
task_env=task_env,
328+
min_available_memory_mb=min_available_memory_mb,
323329
)
324330

325331
def basic(
@@ -369,6 +375,7 @@ def basic(
369375
extra_output_container: Optional[Container] = None,
370376
crashes: Optional[Container] = None,
371377
task_env: Optional[Dict[str, str]] = None,
378+
min_available_memory_mb: Optional[int] = None,
372379
) -> Optional[Job]:
373380
"""
374381
Basic libfuzzer job
@@ -507,6 +514,7 @@ def basic(
507514
tools=tools,
508515
task_env=task_env,
509516
target_timeout=target_timeout,
517+
min_available_memory_mb=min_available_memory_mb,
510518
)
511519

512520
self.logger.info("done creating tasks")
@@ -543,6 +551,7 @@ def merge(
543551
no_check_fuzzer_help: bool = False,
544552
extra_setup_container: Optional[Container] = None,
545553
task_env: Optional[Dict[str, str]] = None,
554+
min_available_memory_mb: Optional[int] = None,
546555
) -> Optional[Job]:
547556
"""
548557
libfuzzer merge task
@@ -657,6 +666,7 @@ def merge(
657666
preserve_existing_outputs=preserve_existing_outputs,
658667
check_fuzzer_help=check_fuzzer_help,
659668
task_env=task_env,
669+
min_available_memory_mb=min_available_memory_mb,
660670
)
661671

662672
self.logger.info("done creating tasks")
@@ -698,6 +708,7 @@ def dotnet(
698708
extra_setup_container: Optional[Container] = None,
699709
crashes: Optional[Container] = None,
700710
task_env: Optional[Dict[str, str]] = None,
711+
min_available_memory_mb: Optional[int] = None,
701712
) -> Optional[Job]:
702713
pool = self.onefuzz.pools.get(pool_name)
703714

@@ -820,6 +831,7 @@ def dotnet(
820831
expect_crash_on_failure=expect_crash_on_failure,
821832
check_fuzzer_help=False,
822833
task_env=task_env,
834+
min_available_memory_mb=min_available_memory_mb,
823835
)
824836

825837
# Ensure the fuzzing task starts before we schedule the coverage and
@@ -874,6 +886,7 @@ def dotnet(
874886
debug=debug,
875887
colocate=colocate_all_tasks or colocate_secondary_tasks,
876888
task_env=task_env,
889+
min_available_memory_mb=min_available_memory_mb,
877890
)
878891

879892
report_containers = [
@@ -915,6 +928,7 @@ def dotnet(
915928
debug=debug,
916929
colocate=colocate_all_tasks or colocate_secondary_tasks,
917930
task_env=task_env,
931+
min_available_memory_mb=min_available_memory_mb,
918932
)
919933

920934
self.logger.info("done creating tasks")
@@ -956,6 +970,7 @@ def qemu_user(
956970
crashes: Optional[Container] = None,
957971
readonly_inputs: Optional[Container] = None,
958972
task_env: Optional[Dict[str, str]] = None,
973+
min_available_memory_mb: Optional[int] = None,
959974
) -> Optional[Job]:
960975
"""
961976
libfuzzer tasks, wrapped via qemu-user (PREVIEW FEATURE)
@@ -1125,6 +1140,7 @@ def qemu_user(
11251140
expect_crash_on_failure=False,
11261141
check_fuzzer_help=check_fuzzer_help,
11271142
task_env=task_env,
1143+
min_available_memory_mb=min_available_memory_mb,
11281144
)
11291145

11301146
report_containers = [
@@ -1167,6 +1183,7 @@ def qemu_user(
11671183
expect_crash_on_failure=False,
11681184
check_fuzzer_help=check_fuzzer_help,
11691185
task_env=task_env,
1186+
min_available_memory_mb=min_available_memory_mb,
11701187
)
11711188

11721189
self.logger.info("done creating tasks")

src/cli/onefuzz/templates/ossfuzz.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ def libfuzzer(
120120
debug: Optional[List[TaskDebugFlag]] = None,
121121
ensemble_sync_delay: Optional[int] = None,
122122
extra_setup_container: Optional[Container] = None,
123+
min_available_memory_mb: Optional[int] = None,
123124
) -> None:
124125
"""
125126
OssFuzz style libfuzzer jobs
@@ -257,6 +258,7 @@ def libfuzzer(
257258
tags=helper.tags,
258259
debug=debug,
259260
ensemble_sync_delay=ensemble_sync_delay,
261+
min_available_memory_mb=min_available_memory_mb,
260262
)
261263
helpers.append(helper)
262264
base_helper.wait()

0 commit comments

Comments
 (0)