mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-15 11:28:09 +00:00
Enable dotnet fuzzing (#2273)
Add a new CLI job template, `libfuzzer dotnet_dll`, and supporting server-side definitions.
This commit is contained in:
@ -488,6 +488,14 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"title": "Supervisor Options",
|
"title": "Supervisor Options",
|
||||||
"type": "array"
|
"type": "array"
|
||||||
},
|
},
|
||||||
|
"target_assembly": {
|
||||||
|
"title": "Target Assembly",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"target_class": {
|
||||||
|
"title": "Target Class",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"target_env": {
|
"target_env": {
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -499,6 +507,10 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"title": "Target Exe",
|
"title": "Target Exe",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"target_method": {
|
||||||
|
"title": "Target Method",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"target_options": {
|
"target_options": {
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -555,6 +567,9 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"description": "An enumeration.",
|
"description": "An enumeration.",
|
||||||
"enum": [
|
"enum": [
|
||||||
"coverage",
|
"coverage",
|
||||||
|
"dotnet_coverage",
|
||||||
|
"dotnet_crash_report",
|
||||||
|
"libfuzzer_dotnet_fuzz",
|
||||||
"libfuzzer_fuzz",
|
"libfuzzer_fuzz",
|
||||||
"libfuzzer_coverage",
|
"libfuzzer_coverage",
|
||||||
"libfuzzer_crash_report",
|
"libfuzzer_crash_report",
|
||||||
@ -565,8 +580,7 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"generic_merge",
|
"generic_merge",
|
||||||
"generic_generator",
|
"generic_generator",
|
||||||
"generic_crash_report",
|
"generic_crash_report",
|
||||||
"generic_regression",
|
"generic_regression"
|
||||||
"dotnet_coverage"
|
|
||||||
],
|
],
|
||||||
"title": "TaskType"
|
"title": "TaskType"
|
||||||
},
|
},
|
||||||
@ -1207,6 +1221,9 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"description": "An enumeration.",
|
"description": "An enumeration.",
|
||||||
"enum": [
|
"enum": [
|
||||||
"coverage",
|
"coverage",
|
||||||
|
"dotnet_coverage",
|
||||||
|
"dotnet_crash_report",
|
||||||
|
"libfuzzer_dotnet_fuzz",
|
||||||
"libfuzzer_fuzz",
|
"libfuzzer_fuzz",
|
||||||
"libfuzzer_coverage",
|
"libfuzzer_coverage",
|
||||||
"libfuzzer_crash_report",
|
"libfuzzer_crash_report",
|
||||||
@ -1217,8 +1234,7 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"generic_merge",
|
"generic_merge",
|
||||||
"generic_generator",
|
"generic_generator",
|
||||||
"generic_crash_report",
|
"generic_crash_report",
|
||||||
"generic_regression",
|
"generic_regression"
|
||||||
"dotnet_coverage"
|
|
||||||
],
|
],
|
||||||
"title": "TaskType"
|
"title": "TaskType"
|
||||||
},
|
},
|
||||||
@ -2381,6 +2397,14 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"title": "Supervisor Options",
|
"title": "Supervisor Options",
|
||||||
"type": "array"
|
"type": "array"
|
||||||
},
|
},
|
||||||
|
"target_assembly": {
|
||||||
|
"title": "Target Assembly",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"target_class": {
|
||||||
|
"title": "Target Class",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"target_env": {
|
"target_env": {
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -2392,6 +2416,10 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"title": "Target Exe",
|
"title": "Target Exe",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"target_method": {
|
||||||
|
"title": "Target Method",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"target_options": {
|
"target_options": {
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -2448,6 +2476,9 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"description": "An enumeration.",
|
"description": "An enumeration.",
|
||||||
"enum": [
|
"enum": [
|
||||||
"coverage",
|
"coverage",
|
||||||
|
"dotnet_coverage",
|
||||||
|
"dotnet_crash_report",
|
||||||
|
"libfuzzer_dotnet_fuzz",
|
||||||
"libfuzzer_fuzz",
|
"libfuzzer_fuzz",
|
||||||
"libfuzzer_coverage",
|
"libfuzzer_coverage",
|
||||||
"libfuzzer_crash_report",
|
"libfuzzer_crash_report",
|
||||||
@ -2458,8 +2489,7 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"generic_merge",
|
"generic_merge",
|
||||||
"generic_generator",
|
"generic_generator",
|
||||||
"generic_crash_report",
|
"generic_crash_report",
|
||||||
"generic_regression",
|
"generic_regression"
|
||||||
"dotnet_coverage"
|
|
||||||
],
|
],
|
||||||
"title": "TaskType"
|
"title": "TaskType"
|
||||||
},
|
},
|
||||||
@ -3097,6 +3127,14 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"title": "Supervisor Options",
|
"title": "Supervisor Options",
|
||||||
"type": "array"
|
"type": "array"
|
||||||
},
|
},
|
||||||
|
"target_assembly": {
|
||||||
|
"title": "Target Assembly",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"target_class": {
|
||||||
|
"title": "Target Class",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"target_env": {
|
"target_env": {
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -3108,6 +3146,10 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"title": "Target Exe",
|
"title": "Target Exe",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"target_method": {
|
||||||
|
"title": "Target Method",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"target_options": {
|
"target_options": {
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -3164,6 +3206,9 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"description": "An enumeration.",
|
"description": "An enumeration.",
|
||||||
"enum": [
|
"enum": [
|
||||||
"coverage",
|
"coverage",
|
||||||
|
"dotnet_coverage",
|
||||||
|
"dotnet_crash_report",
|
||||||
|
"libfuzzer_dotnet_fuzz",
|
||||||
"libfuzzer_fuzz",
|
"libfuzzer_fuzz",
|
||||||
"libfuzzer_coverage",
|
"libfuzzer_coverage",
|
||||||
"libfuzzer_crash_report",
|
"libfuzzer_crash_report",
|
||||||
@ -3174,8 +3219,7 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"generic_merge",
|
"generic_merge",
|
||||||
"generic_generator",
|
"generic_generator",
|
||||||
"generic_crash_report",
|
"generic_crash_report",
|
||||||
"generic_regression",
|
"generic_regression"
|
||||||
"dotnet_coverage"
|
|
||||||
],
|
],
|
||||||
"title": "TaskType"
|
"title": "TaskType"
|
||||||
},
|
},
|
||||||
@ -3604,6 +3648,14 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"title": "Supervisor Options",
|
"title": "Supervisor Options",
|
||||||
"type": "array"
|
"type": "array"
|
||||||
},
|
},
|
||||||
|
"target_assembly": {
|
||||||
|
"title": "Target Assembly",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"target_class": {
|
||||||
|
"title": "Target Class",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"target_env": {
|
"target_env": {
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -3615,6 +3667,10 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"title": "Target Exe",
|
"title": "Target Exe",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"target_method": {
|
||||||
|
"title": "Target Method",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"target_options": {
|
"target_options": {
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -3671,6 +3727,9 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"description": "An enumeration.",
|
"description": "An enumeration.",
|
||||||
"enum": [
|
"enum": [
|
||||||
"coverage",
|
"coverage",
|
||||||
|
"dotnet_coverage",
|
||||||
|
"dotnet_crash_report",
|
||||||
|
"libfuzzer_dotnet_fuzz",
|
||||||
"libfuzzer_fuzz",
|
"libfuzzer_fuzz",
|
||||||
"libfuzzer_coverage",
|
"libfuzzer_coverage",
|
||||||
"libfuzzer_crash_report",
|
"libfuzzer_crash_report",
|
||||||
@ -3681,8 +3740,7 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"generic_merge",
|
"generic_merge",
|
||||||
"generic_generator",
|
"generic_generator",
|
||||||
"generic_crash_report",
|
"generic_crash_report",
|
||||||
"generic_regression",
|
"generic_regression"
|
||||||
"dotnet_coverage"
|
|
||||||
],
|
],
|
||||||
"title": "TaskType"
|
"title": "TaskType"
|
||||||
},
|
},
|
||||||
@ -4054,6 +4112,14 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"title": "Supervisor Options",
|
"title": "Supervisor Options",
|
||||||
"type": "array"
|
"type": "array"
|
||||||
},
|
},
|
||||||
|
"target_assembly": {
|
||||||
|
"title": "Target Assembly",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"target_class": {
|
||||||
|
"title": "Target Class",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"target_env": {
|
"target_env": {
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -4065,6 +4131,10 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"title": "Target Exe",
|
"title": "Target Exe",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"target_method": {
|
||||||
|
"title": "Target Method",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"target_options": {
|
"target_options": {
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -4121,6 +4191,9 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"description": "An enumeration.",
|
"description": "An enumeration.",
|
||||||
"enum": [
|
"enum": [
|
||||||
"coverage",
|
"coverage",
|
||||||
|
"dotnet_coverage",
|
||||||
|
"dotnet_crash_report",
|
||||||
|
"libfuzzer_dotnet_fuzz",
|
||||||
"libfuzzer_fuzz",
|
"libfuzzer_fuzz",
|
||||||
"libfuzzer_coverage",
|
"libfuzzer_coverage",
|
||||||
"libfuzzer_crash_report",
|
"libfuzzer_crash_report",
|
||||||
@ -4131,8 +4204,7 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"generic_merge",
|
"generic_merge",
|
||||||
"generic_generator",
|
"generic_generator",
|
||||||
"generic_crash_report",
|
"generic_crash_report",
|
||||||
"generic_regression",
|
"generic_regression"
|
||||||
"dotnet_coverage"
|
|
||||||
],
|
],
|
||||||
"title": "TaskType"
|
"title": "TaskType"
|
||||||
},
|
},
|
||||||
@ -4478,6 +4550,14 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"title": "Supervisor Options",
|
"title": "Supervisor Options",
|
||||||
"type": "array"
|
"type": "array"
|
||||||
},
|
},
|
||||||
|
"target_assembly": {
|
||||||
|
"title": "Target Assembly",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"target_class": {
|
||||||
|
"title": "Target Class",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"target_env": {
|
"target_env": {
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -4489,6 +4569,10 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"title": "Target Exe",
|
"title": "Target Exe",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"target_method": {
|
||||||
|
"title": "Target Method",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"target_options": {
|
"target_options": {
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -4559,6 +4643,9 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"description": "An enumeration.",
|
"description": "An enumeration.",
|
||||||
"enum": [
|
"enum": [
|
||||||
"coverage",
|
"coverage",
|
||||||
|
"dotnet_coverage",
|
||||||
|
"dotnet_crash_report",
|
||||||
|
"libfuzzer_dotnet_fuzz",
|
||||||
"libfuzzer_fuzz",
|
"libfuzzer_fuzz",
|
||||||
"libfuzzer_coverage",
|
"libfuzzer_coverage",
|
||||||
"libfuzzer_crash_report",
|
"libfuzzer_crash_report",
|
||||||
@ -4569,8 +4656,7 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"generic_merge",
|
"generic_merge",
|
||||||
"generic_generator",
|
"generic_generator",
|
||||||
"generic_crash_report",
|
"generic_crash_report",
|
||||||
"generic_regression",
|
"generic_regression"
|
||||||
"dotnet_coverage"
|
|
||||||
],
|
],
|
||||||
"title": "TaskType"
|
"title": "TaskType"
|
||||||
},
|
},
|
||||||
@ -4929,6 +5015,14 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"title": "Supervisor Options",
|
"title": "Supervisor Options",
|
||||||
"type": "array"
|
"type": "array"
|
||||||
},
|
},
|
||||||
|
"target_assembly": {
|
||||||
|
"title": "Target Assembly",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"target_class": {
|
||||||
|
"title": "Target Class",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"target_env": {
|
"target_env": {
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -4940,6 +5034,10 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"title": "Target Exe",
|
"title": "Target Exe",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"target_method": {
|
||||||
|
"title": "Target Method",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"target_options": {
|
"target_options": {
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -4996,6 +5094,9 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"description": "An enumeration.",
|
"description": "An enumeration.",
|
||||||
"enum": [
|
"enum": [
|
||||||
"coverage",
|
"coverage",
|
||||||
|
"dotnet_coverage",
|
||||||
|
"dotnet_crash_report",
|
||||||
|
"libfuzzer_dotnet_fuzz",
|
||||||
"libfuzzer_fuzz",
|
"libfuzzer_fuzz",
|
||||||
"libfuzzer_coverage",
|
"libfuzzer_coverage",
|
||||||
"libfuzzer_crash_report",
|
"libfuzzer_crash_report",
|
||||||
@ -5006,8 +5107,7 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"generic_merge",
|
"generic_merge",
|
||||||
"generic_generator",
|
"generic_generator",
|
||||||
"generic_crash_report",
|
"generic_crash_report",
|
||||||
"generic_regression",
|
"generic_regression"
|
||||||
"dotnet_coverage"
|
|
||||||
],
|
],
|
||||||
"title": "TaskType"
|
"title": "TaskType"
|
||||||
},
|
},
|
||||||
@ -6664,6 +6764,14 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"title": "Supervisor Options",
|
"title": "Supervisor Options",
|
||||||
"type": "array"
|
"type": "array"
|
||||||
},
|
},
|
||||||
|
"target_assembly": {
|
||||||
|
"title": "Target Assembly",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"target_class": {
|
||||||
|
"title": "Target Class",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"target_env": {
|
"target_env": {
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -6675,6 +6783,10 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"title": "Target Exe",
|
"title": "Target Exe",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"target_method": {
|
||||||
|
"title": "Target Method",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"target_options": {
|
"target_options": {
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -6745,6 +6857,9 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"description": "An enumeration.",
|
"description": "An enumeration.",
|
||||||
"enum": [
|
"enum": [
|
||||||
"coverage",
|
"coverage",
|
||||||
|
"dotnet_coverage",
|
||||||
|
"dotnet_crash_report",
|
||||||
|
"libfuzzer_dotnet_fuzz",
|
||||||
"libfuzzer_fuzz",
|
"libfuzzer_fuzz",
|
||||||
"libfuzzer_coverage",
|
"libfuzzer_coverage",
|
||||||
"libfuzzer_crash_report",
|
"libfuzzer_crash_report",
|
||||||
@ -6755,8 +6870,7 @@ If webhook is set to have Event Grid message format then the payload will look a
|
|||||||
"generic_merge",
|
"generic_merge",
|
||||||
"generic_generator",
|
"generic_generator",
|
||||||
"generic_crash_report",
|
"generic_crash_report",
|
||||||
"generic_regression",
|
"generic_regression"
|
||||||
"dotnet_coverage"
|
|
||||||
],
|
],
|
||||||
"title": "TaskType"
|
"title": "TaskType"
|
||||||
},
|
},
|
||||||
|
@ -61,6 +61,9 @@ public enum TaskState {
|
|||||||
|
|
||||||
public enum TaskType {
|
public enum TaskType {
|
||||||
Coverage,
|
Coverage,
|
||||||
|
DotnetCoverage,
|
||||||
|
DotnetCrashReport,
|
||||||
|
LibfuzzerDotnetFuzz,
|
||||||
LibfuzzerFuzz,
|
LibfuzzerFuzz,
|
||||||
LibfuzzerCoverage,
|
LibfuzzerCoverage,
|
||||||
LibfuzzerCrashReport,
|
LibfuzzerCrashReport,
|
||||||
@ -72,7 +75,6 @@ public enum TaskType {
|
|||||||
GenericGenerator,
|
GenericGenerator,
|
||||||
GenericCrashReport,
|
GenericCrashReport,
|
||||||
GenericRegression,
|
GenericRegression,
|
||||||
DotnetCoverage,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Os {
|
public enum Os {
|
||||||
@ -269,7 +271,10 @@ public enum TaskFeature {
|
|||||||
ReportList,
|
ReportList,
|
||||||
MinimizedStackDepth,
|
MinimizedStackDepth,
|
||||||
CoverageFilter,
|
CoverageFilter,
|
||||||
TargetMustUseInput
|
TargetMustUseInput,
|
||||||
|
TargetAssembly,
|
||||||
|
TargetClass,
|
||||||
|
TargetMethod,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -200,7 +200,10 @@ public record TaskDetails(
|
|||||||
bool? PreserveExistingOutputs = null,
|
bool? PreserveExistingOutputs = null,
|
||||||
List<string>? ReportList = null,
|
List<string>? ReportList = null,
|
||||||
long? MinimizedStackDepth = null,
|
long? MinimizedStackDepth = null,
|
||||||
string? CoverageFilter = null
|
string? CoverageFilter = null,
|
||||||
|
string? TargetAssembly = null,
|
||||||
|
string? TargetClass = null,
|
||||||
|
string? TargetMethod = null
|
||||||
);
|
);
|
||||||
|
|
||||||
public record TaskVm(
|
public record TaskVm(
|
||||||
@ -919,6 +922,9 @@ public record TaskUnitConfig(
|
|||||||
public List<string>? ReportList { get; set; }
|
public List<string>? ReportList { get; set; }
|
||||||
public long? MinimizedStackDepth { get; set; }
|
public long? MinimizedStackDepth { get; set; }
|
||||||
public string? CoverageFilter { get; set; }
|
public string? CoverageFilter { get; set; }
|
||||||
|
public string? TargetAssembly { get; set; }
|
||||||
|
public string? TargetClass { get; set; }
|
||||||
|
public string? TargetMethod { get; set; }
|
||||||
|
|
||||||
// from here forwards are Container definitions. These need to be inline
|
// from here forwards are Container definitions. These need to be inline
|
||||||
// with TaskDefinitions and ContainerTypes
|
// with TaskDefinitions and ContainerTypes
|
||||||
|
@ -262,6 +262,18 @@ public class Config : IConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (definition.Features.Contains(TaskFeature.TargetAssembly)) {
|
||||||
|
config.TargetAssembly = task.Config.Task.TargetAssembly;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (definition.Features.Contains(TaskFeature.TargetClass)) {
|
||||||
|
config.TargetClass = task.Config.Task.TargetClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (definition.Features.Contains(TaskFeature.TargetMethod)) {
|
||||||
|
config.TargetMethod = task.Config.Task.TargetMethod;
|
||||||
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,12 +35,153 @@ public static class Defs {
|
|||||||
ContainerPermission.List |
|
ContainerPermission.List |
|
||||||
ContainerPermission.Read |
|
ContainerPermission.Read |
|
||||||
ContainerPermission.Write
|
ContainerPermission.Write
|
||||||
|
|
||||||
)},
|
)},
|
||||||
MonitorQueue: ContainerType.ReadonlyInputs)
|
MonitorQueue: ContainerType.ReadonlyInputs)
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
TaskType.DotnetCoverage, new TaskDefinition(
|
||||||
|
Features: new[] {
|
||||||
|
TaskFeature.TargetExe,
|
||||||
|
TaskFeature.TargetEnv,
|
||||||
|
TaskFeature.TargetOptions,
|
||||||
|
TaskFeature.TargetTimeout,
|
||||||
|
TaskFeature.CoverageFilter,
|
||||||
|
TaskFeature.TargetMustUseInput,
|
||||||
|
},
|
||||||
|
Vm: new VmDefinition(Compare: Compare.Equal, Value:1),
|
||||||
|
Containers: new [] {
|
||||||
|
new ContainerDefinition(
|
||||||
|
Type:ContainerType.Setup,
|
||||||
|
Compare: Compare.Equal,
|
||||||
|
Value:1,
|
||||||
|
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||||
|
),
|
||||||
|
new ContainerDefinition(
|
||||||
|
Type:ContainerType.ReadonlyInputs,
|
||||||
|
Compare: Compare.AtLeast,
|
||||||
|
Value:1,
|
||||||
|
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||||
|
),
|
||||||
|
new ContainerDefinition(
|
||||||
|
Type:ContainerType.Coverage,
|
||||||
|
Compare: Compare.Equal,
|
||||||
|
Value:1,
|
||||||
|
Permissions:
|
||||||
|
ContainerPermission.List |
|
||||||
|
ContainerPermission.Read |
|
||||||
|
ContainerPermission.Write
|
||||||
|
|
||||||
|
),
|
||||||
|
new ContainerDefinition(
|
||||||
|
Type:ContainerType.Tools,
|
||||||
|
Compare: Compare.Equal,
|
||||||
|
Value:1,
|
||||||
|
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||||
|
),
|
||||||
|
},
|
||||||
|
MonitorQueue: ContainerType.ReadonlyInputs)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TaskType.DotnetCrashReport, new TaskDefinition(
|
||||||
|
Features: new[] {
|
||||||
|
TaskFeature.TargetExe,
|
||||||
|
TaskFeature.TargetEnv,
|
||||||
|
TaskFeature.TargetOptions,
|
||||||
|
TaskFeature.TargetTimeout,
|
||||||
|
TaskFeature.CheckRetryCount,
|
||||||
|
TaskFeature.CheckFuzzerHelp,
|
||||||
|
TaskFeature.MinimizedStackDepth,
|
||||||
|
},
|
||||||
|
Vm: new VmDefinition(Compare: Compare.AtLeast, Value: 1),
|
||||||
|
Containers: new[] {
|
||||||
|
new ContainerDefinition(
|
||||||
|
Type:ContainerType.Setup,
|
||||||
|
Compare: Compare.Equal,
|
||||||
|
Value:1,
|
||||||
|
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||||
|
),
|
||||||
|
new ContainerDefinition(
|
||||||
|
Type:ContainerType.Crashes,
|
||||||
|
Compare: Compare.Equal,
|
||||||
|
Value:1,
|
||||||
|
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||||
|
),
|
||||||
|
new ContainerDefinition(
|
||||||
|
Type:ContainerType.Reports,
|
||||||
|
Compare: Compare.AtMost,
|
||||||
|
Value:1,
|
||||||
|
Permissions: ContainerPermission.Write
|
||||||
|
),
|
||||||
|
new ContainerDefinition(
|
||||||
|
Type: ContainerType.UniqueReports,
|
||||||
|
Compare: Compare.AtMost,
|
||||||
|
Value: 1,
|
||||||
|
Permissions: ContainerPermission.Write
|
||||||
|
),
|
||||||
|
new ContainerDefinition(
|
||||||
|
Type: ContainerType.NoRepro,
|
||||||
|
Compare: Compare.AtMost,
|
||||||
|
Value: 1,
|
||||||
|
Permissions: ContainerPermission.Write
|
||||||
|
),
|
||||||
|
new ContainerDefinition(
|
||||||
|
Type:ContainerType.Tools,
|
||||||
|
Compare: Compare.Equal,
|
||||||
|
Value:1,
|
||||||
|
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||||
|
),
|
||||||
|
},
|
||||||
|
MonitorQueue: ContainerType.Crashes
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TaskType.LibfuzzerDotnetFuzz, new TaskDefinition(
|
||||||
|
Features: new[] {
|
||||||
|
TaskFeature.TargetExe,
|
||||||
|
TaskFeature.TargetEnv,
|
||||||
|
TaskFeature.TargetOptions,
|
||||||
|
TaskFeature.TargetWorkers,
|
||||||
|
TaskFeature.EnsembleSyncDelay,
|
||||||
|
TaskFeature.CheckFuzzerHelp,
|
||||||
|
TaskFeature.ExpectCrashOnFailure,
|
||||||
|
TaskFeature.TargetAssembly,
|
||||||
|
TaskFeature.TargetClass,
|
||||||
|
TaskFeature.TargetMethod,
|
||||||
|
},
|
||||||
|
Vm: new VmDefinition(Compare: Compare.AtLeast, Value: 1),
|
||||||
|
Containers: new[] {
|
||||||
|
new ContainerDefinition(
|
||||||
|
Type:ContainerType.Setup,
|
||||||
|
Compare: Compare.Equal,
|
||||||
|
Value:1,
|
||||||
|
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||||
|
),
|
||||||
|
new ContainerDefinition(
|
||||||
|
Type:ContainerType.Crashes,
|
||||||
|
Compare: Compare.Equal,
|
||||||
|
Value:1,
|
||||||
|
Permissions: ContainerPermission.Write
|
||||||
|
),
|
||||||
|
new ContainerDefinition(
|
||||||
|
Type: ContainerType.Inputs,
|
||||||
|
Compare: Compare.Equal,
|
||||||
|
Value: 1,
|
||||||
|
Permissions: ContainerPermission.Write | ContainerPermission.Read | ContainerPermission.List
|
||||||
|
),
|
||||||
|
new ContainerDefinition(
|
||||||
|
Type: ContainerType.ReadonlyInputs,
|
||||||
|
Compare: Compare.AtLeast,
|
||||||
|
Value: 0,
|
||||||
|
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||||
|
),
|
||||||
|
new ContainerDefinition(
|
||||||
|
Type:ContainerType.Tools,
|
||||||
|
Compare: Compare.Equal,
|
||||||
|
Value:1,
|
||||||
|
Permissions: ContainerPermission.Read | ContainerPermission.List
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)},
|
||||||
{ TaskType.GenericAnalysis ,
|
{ TaskType.GenericAnalysis ,
|
||||||
new TaskDefinition(
|
new TaskDefinition(
|
||||||
Features: new[] {
|
Features: new[] {
|
||||||
@ -555,41 +696,5 @@ public static class Defs {
|
|||||||
),
|
),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{ TaskType.DotnetCoverage ,
|
|
||||||
new TaskDefinition(
|
|
||||||
Features: new[] {
|
|
||||||
TaskFeature.TargetExe,
|
|
||||||
TaskFeature.TargetEnv,
|
|
||||||
TaskFeature.TargetOptions,
|
|
||||||
TaskFeature.TargetTimeout,
|
|
||||||
TaskFeature.CoverageFilter,
|
|
||||||
TaskFeature.TargetMustUseInput,
|
|
||||||
},
|
|
||||||
Vm: new VmDefinition(Compare: Compare.Equal, Value:1),
|
|
||||||
Containers: new [] {
|
|
||||||
new ContainerDefinition(
|
|
||||||
Type:ContainerType.Setup,
|
|
||||||
Compare: Compare.Equal,
|
|
||||||
Value:1,
|
|
||||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
|
||||||
),
|
|
||||||
new ContainerDefinition(
|
|
||||||
Type:ContainerType.ReadonlyInputs,
|
|
||||||
Compare: Compare.AtLeast,
|
|
||||||
Value:1,
|
|
||||||
Permissions: ContainerPermission.Read | ContainerPermission.List
|
|
||||||
),
|
|
||||||
new ContainerDefinition(
|
|
||||||
Type:ContainerType.Coverage,
|
|
||||||
Compare: Compare.Equal,
|
|
||||||
Value:1,
|
|
||||||
Permissions:
|
|
||||||
ContainerPermission.List |
|
|
||||||
ContainerPermission.Read |
|
|
||||||
ContainerPermission.Write
|
|
||||||
|
|
||||||
)},
|
|
||||||
MonitorQueue: ContainerType.ReadonlyInputs)
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||||
|
use crate::local::coverage;
|
||||||
use crate::local::{
|
use crate::local::{
|
||||||
common::add_common_config, generic_analysis, generic_crash_report, generic_generator,
|
common::add_common_config, generic_analysis, generic_crash_report, generic_generator,
|
||||||
libfuzzer, libfuzzer_crash_report, libfuzzer_fuzz, libfuzzer_merge, libfuzzer_regression,
|
libfuzzer, libfuzzer_crash_report, libfuzzer_fuzz, libfuzzer_merge, libfuzzer_regression,
|
||||||
libfuzzer_test_input, radamsa, test_input, tui::TerminalUi,
|
libfuzzer_test_input, radamsa, test_input, tui::TerminalUi,
|
||||||
};
|
};
|
||||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
|
||||||
use crate::local::{coverage, dotnet_coverage};
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use clap::{App, Arg, SubCommand};
|
use clap::{App, Arg, SubCommand};
|
||||||
use crossterm::tty::IsTty;
|
use crossterm::tty::IsTty;
|
||||||
@ -23,8 +23,6 @@ enum Commands {
|
|||||||
Radamsa,
|
Radamsa,
|
||||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||||
Coverage,
|
Coverage,
|
||||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
|
||||||
DotnetCoverage,
|
|
||||||
LibfuzzerFuzz,
|
LibfuzzerFuzz,
|
||||||
LibfuzzerMerge,
|
LibfuzzerMerge,
|
||||||
LibfuzzerCrashReport,
|
LibfuzzerCrashReport,
|
||||||
@ -61,8 +59,6 @@ pub async fn run(args: clap::ArgMatches<'static>) -> Result<()> {
|
|||||||
match command {
|
match command {
|
||||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||||
Commands::Coverage => coverage::run(&sub_args, event_sender).await,
|
Commands::Coverage => coverage::run(&sub_args, event_sender).await,
|
||||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
|
||||||
Commands::DotnetCoverage => dotnet_coverage::run(&sub_args, event_sender).await,
|
|
||||||
Commands::Radamsa => radamsa::run(&sub_args, event_sender).await,
|
Commands::Radamsa => radamsa::run(&sub_args, event_sender).await,
|
||||||
Commands::LibfuzzerCrashReport => {
|
Commands::LibfuzzerCrashReport => {
|
||||||
libfuzzer_crash_report::run(&sub_args, event_sender).await
|
libfuzzer_crash_report::run(&sub_args, event_sender).await
|
||||||
@ -121,8 +117,6 @@ pub fn args(name: &str) -> App<'static, 'static> {
|
|||||||
let app = match subcommand {
|
let app = match subcommand {
|
||||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||||
Commands::Coverage => coverage::args(subcommand.into()),
|
Commands::Coverage => coverage::args(subcommand.into()),
|
||||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
|
||||||
Commands::DotnetCoverage => dotnet_coverage::args(subcommand.into()),
|
|
||||||
Commands::Radamsa => radamsa::args(subcommand.into()),
|
Commands::Radamsa => radamsa::args(subcommand.into()),
|
||||||
Commands::LibfuzzerCrashReport => libfuzzer_crash_report::args(subcommand.into()),
|
Commands::LibfuzzerCrashReport => libfuzzer_crash_report::args(subcommand.into()),
|
||||||
Commands::LibfuzzerFuzz => libfuzzer_fuzz::args(subcommand.into()),
|
Commands::LibfuzzerFuzz => libfuzzer_fuzz::args(subcommand.into()),
|
||||||
|
@ -29,8 +29,6 @@ pub const CHECK_RETRY_COUNT: &str = "check_retry_count";
|
|||||||
pub const DISABLE_CHECK_QUEUE: &str = "disable_check_queue";
|
pub const DISABLE_CHECK_QUEUE: &str = "disable_check_queue";
|
||||||
pub const UNIQUE_REPORTS_DIR: &str = "unique_reports_dir";
|
pub const UNIQUE_REPORTS_DIR: &str = "unique_reports_dir";
|
||||||
pub const COVERAGE_DIR: &str = "coverage_dir";
|
pub const COVERAGE_DIR: &str = "coverage_dir";
|
||||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
|
||||||
pub const DOTNET_COVERAGE_DIR: &str = "dotnet_coverage_dir";
|
|
||||||
pub const READONLY_INPUTS: &str = "readonly_inputs_dir";
|
pub const READONLY_INPUTS: &str = "readonly_inputs_dir";
|
||||||
pub const CHECK_ASAN_LOG: &str = "check_asan_log";
|
pub const CHECK_ASAN_LOG: &str = "check_asan_log";
|
||||||
pub const TOOLS_DIR: &str = "tools_dir";
|
pub const TOOLS_DIR: &str = "tools_dir";
|
||||||
|
@ -1,124 +0,0 @@
|
|||||||
// Copyright (c) Microsoft Corporation.
|
|
||||||
// Licensed under the MIT License.
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
local::common::{
|
|
||||||
build_local_context, get_cmd_arg, get_cmd_env, get_cmd_exe, get_synced_dir,
|
|
||||||
get_synced_dirs, CmdType, SyncCountDirMonitor, UiEvent, COVERAGE_DIR, INPUTS_DIR,
|
|
||||||
READONLY_INPUTS, TARGET_ENV, TARGET_EXE, TARGET_OPTIONS, TARGET_TIMEOUT,
|
|
||||||
},
|
|
||||||
tasks::{
|
|
||||||
config::CommonConfig,
|
|
||||||
coverage::dotnet::{Config, DotnetCoverageTask},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use clap::{App, Arg, SubCommand};
|
|
||||||
use flume::Sender;
|
|
||||||
use storage_queue::QueueClient;
|
|
||||||
|
|
||||||
pub fn build_shared_args(local_job: bool) -> Vec<Arg<'static, 'static>> {
|
|
||||||
let mut args = vec![
|
|
||||||
Arg::with_name(TARGET_EXE)
|
|
||||||
.long(TARGET_EXE)
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true),
|
|
||||||
Arg::with_name(TARGET_ENV)
|
|
||||||
.long(TARGET_ENV)
|
|
||||||
.takes_value(true)
|
|
||||||
.multiple(true),
|
|
||||||
Arg::with_name(TARGET_OPTIONS)
|
|
||||||
.long(TARGET_OPTIONS)
|
|
||||||
.default_value("{input}")
|
|
||||||
.takes_value(true)
|
|
||||||
.value_delimiter(" ")
|
|
||||||
.help("Use a quoted string with space separation to denote multiple arguments"),
|
|
||||||
Arg::with_name(TARGET_TIMEOUT)
|
|
||||||
.takes_value(true)
|
|
||||||
.long(TARGET_TIMEOUT),
|
|
||||||
Arg::with_name(COVERAGE_DIR)
|
|
||||||
.takes_value(true)
|
|
||||||
.required(!local_job)
|
|
||||||
.long(COVERAGE_DIR),
|
|
||||||
];
|
|
||||||
if local_job {
|
|
||||||
args.push(
|
|
||||||
Arg::with_name(INPUTS_DIR)
|
|
||||||
.long(INPUTS_DIR)
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
args.push(
|
|
||||||
Arg::with_name(READONLY_INPUTS)
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.long(READONLY_INPUTS)
|
|
||||||
.multiple(true),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
args
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build_coverage_config(
|
|
||||||
args: &clap::ArgMatches<'_>,
|
|
||||||
local_job: bool,
|
|
||||||
input_queue: Option<QueueClient>,
|
|
||||||
common: CommonConfig,
|
|
||||||
event_sender: Option<Sender<UiEvent>>,
|
|
||||||
) -> Result<Config> {
|
|
||||||
let target_exe = get_cmd_exe(CmdType::Target, args)?.into();
|
|
||||||
let target_env = get_cmd_env(CmdType::Target, args)?;
|
|
||||||
let target_options = get_cmd_arg(CmdType::Target, args);
|
|
||||||
let target_timeout = value_t!(args, TARGET_TIMEOUT, u64).ok();
|
|
||||||
|
|
||||||
let readonly_inputs = if local_job {
|
|
||||||
info!("Took inputs_dir");
|
|
||||||
vec![
|
|
||||||
get_synced_dir(INPUTS_DIR, common.job_id, common.task_id, args)?
|
|
||||||
.monitor_count(&event_sender)?,
|
|
||||||
]
|
|
||||||
} else {
|
|
||||||
get_synced_dirs(READONLY_INPUTS, common.job_id, common.task_id, args)?
|
|
||||||
.into_iter()
|
|
||||||
.map(|sd| sd.monitor_count(&event_sender))
|
|
||||||
.collect::<Result<Vec<_>>>()?
|
|
||||||
};
|
|
||||||
|
|
||||||
let coverage = get_synced_dir(COVERAGE_DIR, common.job_id, common.task_id, args)?
|
|
||||||
.monitor_count(&event_sender)?;
|
|
||||||
|
|
||||||
let config = Config {
|
|
||||||
target_exe,
|
|
||||||
target_env,
|
|
||||||
target_options,
|
|
||||||
target_timeout,
|
|
||||||
input_queue,
|
|
||||||
readonly_inputs,
|
|
||||||
coverage,
|
|
||||||
common,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEvent>>) -> Result<()> {
|
|
||||||
let context = build_local_context(args, true, event_sender.clone())?;
|
|
||||||
let config = build_coverage_config(
|
|
||||||
args,
|
|
||||||
false,
|
|
||||||
None,
|
|
||||||
context.common_config.clone(),
|
|
||||||
event_sender,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let mut task = DotnetCoverageTask::new(config);
|
|
||||||
task.run().await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn args(name: &'static str) -> App<'static, 'static> {
|
|
||||||
SubCommand::with_name(name)
|
|
||||||
.about("execute a local-only coverage task")
|
|
||||||
.args(&build_shared_args(false))
|
|
||||||
}
|
|
@ -1,6 +1,11 @@
|
|||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||||
|
use crate::{
|
||||||
|
local::{common::COVERAGE_DIR, coverage, coverage::build_shared_args as build_coverage_args},
|
||||||
|
tasks::coverage::generic::CoverageTask,
|
||||||
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
local::{
|
local::{
|
||||||
common::{
|
common::{
|
||||||
@ -20,17 +25,6 @@ use crate::{
|
|||||||
regression::libfuzzer::LibFuzzerRegressionTask, report::libfuzzer_report::ReportTask,
|
regression::libfuzzer::LibFuzzerRegressionTask, report::libfuzzer_report::ReportTask,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
|
||||||
use crate::{
|
|
||||||
local::{
|
|
||||||
common::{COVERAGE_DIR, DOTNET_COVERAGE_DIR},
|
|
||||||
coverage,
|
|
||||||
coverage::build_shared_args as build_coverage_args,
|
|
||||||
dotnet_coverage,
|
|
||||||
},
|
|
||||||
tasks::coverage::dotnet::DotnetCoverageTask,
|
|
||||||
tasks::coverage::generic::CoverageTask,
|
|
||||||
};
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::{App, SubCommand};
|
use clap::{App, SubCommand};
|
||||||
use flume::Sender;
|
use flume::Sender;
|
||||||
@ -78,28 +72,6 @@ pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEven
|
|||||||
task_handles.push(crash_report_input_monitor.handle);
|
task_handles.push(crash_report_input_monitor.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
|
||||||
if args.is_present(DOTNET_COVERAGE_DIR) {
|
|
||||||
let coverage_input_monitor =
|
|
||||||
DirectoryMonitorQueue::start_monitoring(crash_dir.clone()).await?;
|
|
||||||
let dotnet_coverage_config = dotnet_coverage::build_coverage_config(
|
|
||||||
args,
|
|
||||||
true,
|
|
||||||
Some(coverage_input_monitor.queue_client),
|
|
||||||
CommonConfig {
|
|
||||||
task_id: Uuid::new_v4(),
|
|
||||||
..context.common_config.clone()
|
|
||||||
},
|
|
||||||
event_sender.clone(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let mut dotnet_coverage = DotnetCoverageTask::new(dotnet_coverage_config);
|
|
||||||
let dotnet_coverage_task = spawn(async move { dotnet_coverage.run().await });
|
|
||||||
|
|
||||||
task_handles.push(dotnet_coverage_task);
|
|
||||||
task_handles.push(coverage_input_monitor.handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||||
if args.is_present(COVERAGE_DIR) {
|
if args.is_present(COVERAGE_DIR) {
|
||||||
let coverage_input_monitor =
|
let coverage_input_monitor =
|
||||||
|
@ -5,8 +5,6 @@ pub mod cmd;
|
|||||||
pub mod common;
|
pub mod common;
|
||||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||||
pub mod coverage;
|
pub mod coverage;
|
||||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
|
||||||
pub mod dotnet_coverage;
|
|
||||||
pub mod generic_analysis;
|
pub mod generic_analysis;
|
||||||
pub mod generic_crash_report;
|
pub mod generic_crash_report;
|
||||||
pub mod generic_generator;
|
pub mod generic_generator;
|
||||||
|
@ -42,6 +42,7 @@ pub struct Config {
|
|||||||
pub input_queue: Option<QueueClient>,
|
pub input_queue: Option<QueueClient>,
|
||||||
pub readonly_inputs: Vec<SyncedDir>,
|
pub readonly_inputs: Vec<SyncedDir>,
|
||||||
pub coverage: SyncedDir,
|
pub coverage: SyncedDir,
|
||||||
|
pub tools: SyncedDir,
|
||||||
|
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub common: CommonConfig,
|
pub common: CommonConfig,
|
||||||
@ -68,6 +69,8 @@ impl DotnetCoverageTask {
|
|||||||
|
|
||||||
pub async fn run(&mut self) -> Result<()> {
|
pub async fn run(&mut self) -> Result<()> {
|
||||||
info!("starting dotnet_coverage task");
|
info!("starting dotnet_coverage task");
|
||||||
|
|
||||||
|
self.config.tools.init_pull().await?;
|
||||||
self.config.coverage.init_pull().await?;
|
self.config.coverage.init_pull().await?;
|
||||||
|
|
||||||
let dotnet_path = dotnet_path()?;
|
let dotnet_path = dotnet_path()?;
|
||||||
@ -257,10 +260,38 @@ impl<'a> TaskContext<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn target_exe(&self) -> Result<String> {
|
||||||
|
let tools_dir = self.config.tools.local_path.to_string_lossy().into_owned();
|
||||||
|
|
||||||
|
// Try to expand `target_exe` with support for `{tools_dir}`.
|
||||||
|
//
|
||||||
|
// Allows using `LibFuzzerDotnetLoader.exe` from a shared tools container.
|
||||||
|
let expand = Expand::new().tools_dir(tools_dir);
|
||||||
|
let expanded = expand.evaluate_value(&self.config.target_exe.to_string_lossy())?;
|
||||||
|
let expanded_path = Path::new(&expanded);
|
||||||
|
|
||||||
|
// Check if `target_exe` was resolved to an absolute path and an existing file.
|
||||||
|
// If so, then the user specified a `target_exe` under the `tools` dir.
|
||||||
|
let is_absolute = expanded_path.is_absolute();
|
||||||
|
let file_exists = fs::metadata(&expanded).await.is_ok();
|
||||||
|
|
||||||
|
if is_absolute && file_exists {
|
||||||
|
// We have found `target_exe`, so skip `setup`-relative expansion.
|
||||||
|
return Ok(expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We haven't yet resolved a local path for `target_exe`. Try the usual
|
||||||
|
// `setup`-relative interpretation of the configured value of `target_exe`.
|
||||||
|
let resolved = try_resolve_setup_relative_path(&self.config.common.setup_dir, expanded)
|
||||||
|
.await?
|
||||||
|
.to_string_lossy()
|
||||||
|
.into_owned();
|
||||||
|
|
||||||
|
Ok(resolved)
|
||||||
|
}
|
||||||
|
|
||||||
async fn command_for_input(&self, input: &Path) -> Result<Command> {
|
async fn command_for_input(&self, input: &Path) -> Result<Command> {
|
||||||
let target_exe =
|
let target_exe = self.target_exe().await?;
|
||||||
try_resolve_setup_relative_path(&self.config.common.setup_dir, &self.config.target_exe)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let expand = Expand::new()
|
let expand = Expand::new()
|
||||||
.machine_id()
|
.machine_id()
|
||||||
@ -288,7 +319,7 @@ impl<'a> TaskContext<'a> {
|
|||||||
.arg(format!(
|
.arg(format!(
|
||||||
"{} {} -- {}",
|
"{} {} -- {}",
|
||||||
dotnet_path.to_string_lossy(),
|
dotnet_path.to_string_lossy(),
|
||||||
self.config.target_exe.canonicalize()?.to_string_lossy(),
|
&target_exe,
|
||||||
target_options.join(" ")
|
target_options.join(" ")
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -1,36 +1,35 @@
|
|||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use onefuzz::fs::set_executable;
|
||||||
use onefuzz::libfuzzer::LibFuzzer;
|
use onefuzz::libfuzzer::LibFuzzer;
|
||||||
|
use onefuzz::syncdir::SyncedDir;
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
|
|
||||||
use crate::tasks::fuzz::libfuzzer::common;
|
use crate::tasks::fuzz::libfuzzer::common;
|
||||||
|
use crate::tasks::utils::try_resolve_setup_relative_path;
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
const LIBFUZZER_DOTNET_PATH: &str =
|
const LIBFUZZER_DOTNET_PATH: &str = "libfuzzer-dotnet/libfuzzer-dotnet";
|
||||||
"/onefuzz/third-party/dotnet-fuzzing-linux/libfuzzer-dotnet/libfuzzer-dotnet";
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
const LIBFUZZER_DOTNET_PATH: &str =
|
const LIBFUZZER_DOTNET_PATH: &str = "libfuzzer-dotnet/libfuzzer-dotnet.exe";
|
||||||
"/onefuzz/third-party/dotnet-fuzzing-windows/libfuzzer-dotnet/libfuzzer-dotnet.exe";
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
const LOADER_PATH: &str =
|
const LOADER_PATH: &str = "LibFuzzerDotnetLoader/LibFuzzerDotnetLoader";
|
||||||
"/onefuzz/third-party/dotnet-fuzzing-linux/LibFuzzerDotnetLoader/LibFuzzerDotnetLoader";
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
const LOADER_PATH: &str =
|
const LOADER_PATH: &str = "LibFuzzerDotnetLoader/LibFuzzerDotnetLoader.exe";
|
||||||
"/onefuzz/third-party/dotnet-fuzzing-windows/LibFuzzerDotnetLoader/LibFuzzerDotnetLoader.exe";
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
const SHARPFUZZ_PATH: &str =
|
const SHARPFUZZ_PATH: &str = "sharpfuzz/SharpFuzz.CommandLine";
|
||||||
"/onefuzz/third-party/dotnet-fuzzing-linux/sharpfuzz/SharpFuzz.CommandLine";
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
const SHARPFUZZ_PATH: &str =
|
const SHARPFUZZ_PATH: &str = "sharpfuzz/SharpFuzz.CommandLine.exe";
|
||||||
"/onefuzz/third-party/dotnet-fuzzing-windows/sharpfuzz/SharpFuzz.CommandLine.exe";
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LibFuzzerDotnet;
|
pub struct LibFuzzerDotnet;
|
||||||
@ -40,6 +39,21 @@ pub struct LibFuzzerDotnetConfig {
|
|||||||
pub target_assembly: String,
|
pub target_assembly: String,
|
||||||
pub target_class: String,
|
pub target_class: String,
|
||||||
pub target_method: String,
|
pub target_method: String,
|
||||||
|
pub tools: SyncedDir,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LibFuzzerDotnetConfig {
|
||||||
|
fn libfuzzer_dotnet_path(&self) -> PathBuf {
|
||||||
|
self.tools.local_path.join(LIBFUZZER_DOTNET_PATH)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn loader_path(&self) -> PathBuf {
|
||||||
|
self.tools.local_path.join(LOADER_PATH)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sharpfuzz_path(&self) -> PathBuf {
|
||||||
|
self.tools.local_path.join(SHARPFUZZ_PATH)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@ -47,12 +61,11 @@ impl common::LibFuzzerType for LibFuzzerDotnet {
|
|||||||
type Config = LibFuzzerDotnetConfig;
|
type Config = LibFuzzerDotnetConfig;
|
||||||
|
|
||||||
async fn from_config(config: &common::Config<Self>) -> Result<LibFuzzer> {
|
async fn from_config(config: &common::Config<Self>) -> Result<LibFuzzer> {
|
||||||
|
let target_assembly = config.target_assembly().await?;
|
||||||
|
|
||||||
// Configure loader to fuzz user target DLL.
|
// Configure loader to fuzz user target DLL.
|
||||||
let mut env = config.target_env.clone();
|
let mut env = config.target_env.clone();
|
||||||
env.insert(
|
env.insert("LIBFUZZER_DOTNET_TARGET_ASSEMBLY".into(), target_assembly);
|
||||||
"LIBFUZZER_DOTNET_TARGET_ASSEMBLY".into(),
|
|
||||||
config.extra.target_assembly.clone(),
|
|
||||||
);
|
|
||||||
env.insert(
|
env.insert(
|
||||||
"LIBFUZZER_DOTNET_TARGET_CLASS".into(),
|
"LIBFUZZER_DOTNET_TARGET_CLASS".into(),
|
||||||
config.extra.target_class.clone(),
|
config.extra.target_class.clone(),
|
||||||
@ -63,10 +76,13 @@ impl common::LibFuzzerType for LibFuzzerDotnet {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let mut options = config.target_options.clone();
|
let mut options = config.target_options.clone();
|
||||||
options.push(format!("--target_path={}", LOADER_PATH));
|
options.push(format!(
|
||||||
|
"--target_path={}",
|
||||||
|
config.extra.loader_path().display()
|
||||||
|
));
|
||||||
|
|
||||||
Ok(LibFuzzer::new(
|
Ok(LibFuzzer::new(
|
||||||
LIBFUZZER_DOTNET_PATH,
|
config.extra.libfuzzer_dotnet_path(),
|
||||||
options,
|
options,
|
||||||
env,
|
env,
|
||||||
&config.common.setup_dir,
|
&config.common.setup_dir,
|
||||||
@ -74,18 +90,29 @@ impl common::LibFuzzerType for LibFuzzerDotnet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn extra_setup(config: &common::Config<Self>) -> Result<()> {
|
async fn extra_setup(config: &common::Config<Self>) -> Result<()> {
|
||||||
|
// Download dotnet fuzzing tools.
|
||||||
|
config.extra.tools.init_pull().await?;
|
||||||
|
|
||||||
|
// Ensure tools are executable.
|
||||||
|
set_executable(&config.extra.tools.local_path).await?;
|
||||||
|
|
||||||
// Use SharpFuzz to statically instrument the target assembly.
|
// Use SharpFuzz to statically instrument the target assembly.
|
||||||
let mut cmd = Command::new(SHARPFUZZ_PATH);
|
let mut cmd = Command::new(config.extra.sharpfuzz_path());
|
||||||
cmd.arg(&config.extra.target_assembly);
|
|
||||||
|
|
||||||
let mut child = cmd.spawn()?;
|
let target_assembly = config.target_assembly().await?;
|
||||||
let status = child.wait().await?;
|
cmd.arg(target_assembly);
|
||||||
|
|
||||||
if !status.success() {
|
cmd.stdout(std::process::Stdio::piped());
|
||||||
|
cmd.stderr(std::process::Stdio::piped());
|
||||||
|
|
||||||
|
let child = cmd.spawn()?;
|
||||||
|
let output = child.wait_with_output().await?;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
anyhow::bail!(
|
anyhow::bail!(
|
||||||
"error instrumenting assembly `{}`: {}",
|
"error instrumenting assembly `{}`: {:?}",
|
||||||
config.extra.target_assembly,
|
config.extra.target_assembly,
|
||||||
status,
|
output,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,5 +120,17 @@ impl common::LibFuzzerType for LibFuzzerDotnet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl common::Config<LibFuzzerDotnet> {
|
||||||
|
async fn target_assembly(&self) -> Result<String> {
|
||||||
|
let resolved =
|
||||||
|
try_resolve_setup_relative_path(&self.common.setup_dir, &self.extra.target_assembly)
|
||||||
|
.await?
|
||||||
|
.to_string_lossy()
|
||||||
|
.into_owned();
|
||||||
|
|
||||||
|
Ok(resolved)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type Config = common::Config<LibFuzzerDotnet>;
|
pub type Config = common::Config<LibFuzzerDotnet>;
|
||||||
pub type LibFuzzerDotnetFuzzTask = common::LibFuzzerFuzzTask<LibFuzzerDotnet>;
|
pub type LibFuzzerDotnetFuzzTask = common::LibFuzzerFuzzTask<LibFuzzerDotnet>;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Output;
|
use std::process::{Output, Stdio};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
@ -14,6 +14,7 @@ pub async fn collect_exception_info(
|
|||||||
args: &[impl AsRef<OsStr>],
|
args: &[impl AsRef<OsStr>],
|
||||||
env: impl IntoIterator<Item = (impl AsRef<OsStr>, impl AsRef<OsStr>)>,
|
env: impl IntoIterator<Item = (impl AsRef<OsStr>, impl AsRef<OsStr>)>,
|
||||||
) -> Result<Option<DotnetExceptionInfo>> {
|
) -> Result<Option<DotnetExceptionInfo>> {
|
||||||
|
// Create temp dir cooperatively.
|
||||||
let tmp_dir = spawn_blocking(tempfile::tempdir).await??;
|
let tmp_dir = spawn_blocking(tempfile::tempdir).await??;
|
||||||
|
|
||||||
let dump_path = tmp_dir.path().join(DUMP_FILE_NAME);
|
let dump_path = tmp_dir.path().join(DUMP_FILE_NAME);
|
||||||
@ -21,13 +22,14 @@ pub async fn collect_exception_info(
|
|||||||
let dump = match collect_dump(args, env, &dump_path).await? {
|
let dump = match collect_dump(args, env, &dump_path).await? {
|
||||||
Some(dump) => dump,
|
Some(dump) => dump,
|
||||||
None => {
|
None => {
|
||||||
|
warn!("no minidump found, expected at {}", dump_path.display());
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let exception = dump.exception().await?;
|
let exception = dump.exception().await?;
|
||||||
|
|
||||||
// Remove temp dir without blocking.
|
// Remove temp dir cooperatively.
|
||||||
spawn_blocking(move || tmp_dir).await?;
|
spawn_blocking(move || tmp_dir).await?;
|
||||||
|
|
||||||
Ok(exception)
|
Ok(exception)
|
||||||
@ -35,15 +37,13 @@ pub async fn collect_exception_info(
|
|||||||
|
|
||||||
const DUMP_FILE_NAME: &str = "tmp.dmp";
|
const DUMP_FILE_NAME: &str = "tmp.dmp";
|
||||||
|
|
||||||
// Assumes `dotnet` >= 6.0.
|
|
||||||
//
|
|
||||||
// See: https://docs.microsoft.com/en-us/dotnet/core/diagnostics/dumps
|
// See: https://docs.microsoft.com/en-us/dotnet/core/diagnostics/dumps
|
||||||
const ENABLE_MINIDUMP_VAR: &str = "DOTNET_DbgEnableMiniDump";
|
const ENABLE_MINIDUMP_VAR: &str = "COMPlus_DbgEnableMiniDump";
|
||||||
const MINIDUMP_TYPE_VAR: &str = "DOTNET_DbgMiniDumpType";
|
const MINIDUMP_TYPE_VAR: &str = "COMPlus_DbgMiniDumpType";
|
||||||
const MINIDUMP_NAME_VAR: &str = "DOTNET_DbgMiniDumpName";
|
const MINIDUMP_NAME_VAR: &str = "COMPlus_DbgMiniDumpName";
|
||||||
|
|
||||||
const MINIDUMP_ENABLE: &str = "1";
|
const MINIDUMP_ENABLE: &str = "1";
|
||||||
const MINIDUMP_TYPE_NORMAL: &str = "1";
|
const MINIDUMP_TYPE_HEAP: &str = "2";
|
||||||
|
|
||||||
// Invoke target with .NET runtime environment vars set to create minidumps.
|
// Invoke target with .NET runtime environment vars set to create minidumps.
|
||||||
//
|
//
|
||||||
@ -55,14 +55,16 @@ async fn collect_dump(
|
|||||||
) -> Result<Option<DotnetDumpFile>> {
|
) -> Result<Option<DotnetDumpFile>> {
|
||||||
let dump_path = dump_path.as_ref();
|
let dump_path = dump_path.as_ref();
|
||||||
|
|
||||||
let mut cmd = Command::new("dotnet");
|
let dotnet = dotnet_path()?;
|
||||||
|
let mut cmd = Command::new(dotnet);
|
||||||
cmd.arg("exec");
|
cmd.arg("exec");
|
||||||
cmd.args(args);
|
cmd.args(args);
|
||||||
|
|
||||||
cmd.envs(env);
|
cmd.envs(env);
|
||||||
|
|
||||||
|
// Set `dotnet` environment vars to enable saving minidumps on crash.
|
||||||
cmd.env(ENABLE_MINIDUMP_VAR, MINIDUMP_ENABLE);
|
cmd.env(ENABLE_MINIDUMP_VAR, MINIDUMP_ENABLE);
|
||||||
cmd.env(MINIDUMP_TYPE_VAR, MINIDUMP_TYPE_NORMAL);
|
cmd.env(MINIDUMP_TYPE_VAR, MINIDUMP_TYPE_HEAP);
|
||||||
cmd.env(MINIDUMP_NAME_VAR, dump_path);
|
cmd.env(MINIDUMP_NAME_VAR, dump_path);
|
||||||
|
|
||||||
let mut child = cmd.spawn()?;
|
let mut child = cmd.spawn()?;
|
||||||
@ -80,6 +82,8 @@ async fn collect_dump(
|
|||||||
|
|
||||||
Ok(Some(dump))
|
Ok(Some(dump))
|
||||||
} else {
|
} else {
|
||||||
|
warn!("target exited nonzero, but no dump file found");
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,12 +106,17 @@ impl DotnetDumpFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn exec_sos_command(&self, sos_cmd: &str) -> Result<Output> {
|
async fn exec_sos_command(&self, sos_cmd: &str) -> Result<Output> {
|
||||||
let mut cmd = Command::new("dotnet");
|
let dotnet_dump = dotnet_dump_path()?;
|
||||||
|
let mut cmd = Command::new(&dotnet_dump);
|
||||||
|
|
||||||
// Run `dotnet-analyze` with a single SOS command on startup, then exit
|
// Run `dotnet-dump analyze` with a single SOS command on startup, then
|
||||||
// the otherwise-interactive SOS session.
|
// exit the otherwise-interactive SOS session.
|
||||||
let dump_path = self.path.display().to_string();
|
let dump_path = self.path.display().to_string();
|
||||||
cmd.args(["dump", "analyze", &dump_path, "-c", sos_cmd, "-c", SOS_EXIT]);
|
let args = ["analyze", &dump_path, "-c", sos_cmd, "-c", SOS_EXIT];
|
||||||
|
cmd.args(args);
|
||||||
|
|
||||||
|
cmd.stderr(Stdio::piped());
|
||||||
|
cmd.stdout(Stdio::piped());
|
||||||
|
|
||||||
let output = cmd.spawn()?.wait_with_output().await?;
|
let output = cmd.spawn()?.wait_with_output().await?;
|
||||||
|
|
||||||
@ -228,5 +237,33 @@ pub fn parse_sos_print_exception_output(text: &str) -> Result<DotnetExceptionInf
|
|||||||
const SOS_EXIT: &str = "exit";
|
const SOS_EXIT: &str = "exit";
|
||||||
const SOS_PRINT_EXCEPTION: &str = "printexception -lines";
|
const SOS_PRINT_EXCEPTION: &str = "printexception -lines";
|
||||||
|
|
||||||
|
fn dotnet_path() -> Result<PathBuf> {
|
||||||
|
let dotnet_root_dir = std::env::var("DOTNET_ROOT")?;
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
let exe_name = "dotnet.exe";
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
let exe_name = "dotnet";
|
||||||
|
|
||||||
|
let exe_path = Path::new(&dotnet_root_dir).join(exe_name);
|
||||||
|
|
||||||
|
Ok(exe_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dotnet_dump_path() -> Result<PathBuf> {
|
||||||
|
let tools_dir = std::env::var("ONEFUZZ_TOOLS")?;
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
let exe_name = "dotnet-dump.exe";
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
let exe_name = "dotnet-dump";
|
||||||
|
|
||||||
|
let exe_path = Path::new(&tools_dir).join(exe_name);
|
||||||
|
|
||||||
|
Ok(exe_path)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
@ -3,16 +3,20 @@
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
env,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use onefuzz::expand::Expand;
|
||||||
|
use onefuzz::fs::set_executable;
|
||||||
use onefuzz::{blob::BlobUrl, sha256, syncdir::SyncedDir};
|
use onefuzz::{blob::BlobUrl, sha256, syncdir::SyncedDir};
|
||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use storage_queue::{Message, QueueClient};
|
use storage_queue::{Message, QueueClient};
|
||||||
|
use tokio::fs;
|
||||||
|
|
||||||
use crate::tasks::report::crash_report::*;
|
use crate::tasks::report::crash_report::*;
|
||||||
use crate::tasks::report::dotnet::common::collect_exception_info;
|
use crate::tasks::report::dotnet::common::collect_exception_info;
|
||||||
@ -37,6 +41,7 @@ pub struct Config {
|
|||||||
pub reports: Option<SyncedDir>,
|
pub reports: Option<SyncedDir>,
|
||||||
pub unique_reports: Option<SyncedDir>,
|
pub unique_reports: Option<SyncedDir>,
|
||||||
pub no_repro: Option<SyncedDir>,
|
pub no_repro: Option<SyncedDir>,
|
||||||
|
pub tools: SyncedDir,
|
||||||
|
|
||||||
#[serde(default = "default_bool_true")]
|
#[serde(default = "default_bool_true")]
|
||||||
pub check_fuzzer_help: bool,
|
pub check_fuzzer_help: bool,
|
||||||
@ -70,12 +75,22 @@ impl DotnetCrashReportTask {
|
|||||||
pub async fn run(&mut self) -> Result<()> {
|
pub async fn run(&mut self) -> Result<()> {
|
||||||
info!("starting dotnet crash report task");
|
info!("starting dotnet crash report task");
|
||||||
|
|
||||||
|
self.config.tools.init_pull().await?;
|
||||||
|
|
||||||
|
set_executable(&self.config.tools.local_path).await?;
|
||||||
|
|
||||||
|
if let Some(crashes) = &self.config.crashes {
|
||||||
|
crashes.init().await?;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(unique_reports) = &self.config.unique_reports {
|
if let Some(unique_reports) = &self.config.unique_reports {
|
||||||
unique_reports.init().await?;
|
unique_reports.init().await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(reports) = &self.config.reports {
|
if let Some(reports) = &self.config.reports {
|
||||||
reports.init().await?;
|
reports.init().await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(no_repro) = &self.config.no_repro {
|
if let Some(no_repro) = &self.config.no_repro {
|
||||||
no_repro.init().await?;
|
no_repro.init().await?;
|
||||||
}
|
}
|
||||||
@ -111,6 +126,36 @@ impl AsanProcessor {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn target_exe(&self) -> Result<String> {
|
||||||
|
let tools_dir = self.config.tools.local_path.to_string_lossy().into_owned();
|
||||||
|
|
||||||
|
// Try to expand `target_exe` with support for `{tools_dir}`.
|
||||||
|
//
|
||||||
|
// Allows using `LibFuzzerDotnetLoader.exe` from a shared tools container.
|
||||||
|
let expand = Expand::new().tools_dir(tools_dir);
|
||||||
|
let expanded = expand.evaluate_value(&self.config.target_exe.to_string_lossy())?;
|
||||||
|
let expanded_path = Path::new(&expanded);
|
||||||
|
|
||||||
|
// Check if `target_exe` was resolved to an absolute path and an existing file.
|
||||||
|
// If so, then the user specified a `target_exe` under the `tools` dir.
|
||||||
|
let is_absolute = expanded_path.is_absolute();
|
||||||
|
let file_exists = fs::metadata(&expanded).await.is_ok();
|
||||||
|
|
||||||
|
if is_absolute && file_exists {
|
||||||
|
// We have found `target_exe`, so skip `setup`-relative expansion.
|
||||||
|
return Ok(expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We haven't yet resolved a local path for `target_exe`. Try the usual
|
||||||
|
// `setup`-relative interpretation of the configured value of `target_exe`.
|
||||||
|
let resolved = try_resolve_setup_relative_path(&self.config.common.setup_dir, expanded)
|
||||||
|
.await?
|
||||||
|
.to_string_lossy()
|
||||||
|
.into_owned();
|
||||||
|
|
||||||
|
Ok(resolved)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn test_input(
|
pub async fn test_input(
|
||||||
&self,
|
&self,
|
||||||
input: &Path,
|
input: &Path,
|
||||||
@ -128,16 +173,31 @@ impl AsanProcessor {
|
|||||||
|
|
||||||
let job_id = self.config.common.task_id;
|
let job_id = self.config.common.task_id;
|
||||||
let task_id = self.config.common.task_id;
|
let task_id = self.config.common.task_id;
|
||||||
let executable =
|
|
||||||
try_resolve_setup_relative_path(&self.config.common.setup_dir, &self.config.target_exe)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let mut args = vec!["dotnet".to_owned(), executable.display().to_string()];
|
let target_exe = self.target_exe().await?;
|
||||||
|
let executable = PathBuf::from(&target_exe);
|
||||||
|
|
||||||
|
let mut args = vec![target_exe];
|
||||||
args.extend(self.config.target_options.clone());
|
args.extend(self.config.target_options.clone());
|
||||||
|
|
||||||
let env = self.config.target_env.clone();
|
let expand = Expand::new()
|
||||||
|
.input_path(input)
|
||||||
|
.setup_dir(&self.config.common.setup_dir);
|
||||||
|
let expanded_args = expand.evaluate(&args)?;
|
||||||
|
|
||||||
let crash_test_result = if let Some(exception) = collect_exception_info(&args, env).await? {
|
let env = {
|
||||||
|
let mut new = HashMap::new();
|
||||||
|
|
||||||
|
for (k, v) in &self.config.target_env {
|
||||||
|
let ev = expand.evaluate_value(v)?;
|
||||||
|
new.insert(k, ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
new
|
||||||
|
};
|
||||||
|
|
||||||
|
let crash_test_result =
|
||||||
|
if let Some(exception) = collect_exception_info(&expanded_args, env).await? {
|
||||||
let call_stack_sha256 = stacktrace_parser::digest_iter(&exception.call_stack, None);
|
let call_stack_sha256 = stacktrace_parser::digest_iter(&exception.call_stack, None);
|
||||||
|
|
||||||
let crash_report = CrashReport {
|
let crash_report = CrashReport {
|
||||||
|
@ -440,6 +440,15 @@ def build_task_config(job: Job, task: Task) -> TaskUnitConfig:
|
|||||||
if coverage_filter is not None:
|
if coverage_filter is not None:
|
||||||
config.coverage_filter = coverage_filter
|
config.coverage_filter = coverage_filter
|
||||||
|
|
||||||
|
if TaskFeature.target_assembly in definition.features:
|
||||||
|
config.target_assembly = task_config.task.target_assembly
|
||||||
|
|
||||||
|
if TaskFeature.target_class in definition.features:
|
||||||
|
config.target_class = task_config.task.target_class
|
||||||
|
|
||||||
|
if TaskFeature.target_method in definition.features:
|
||||||
|
config.target_method = task_config.task.target_method
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,6 +50,152 @@ TASK_DEFINITIONS = {
|
|||||||
],
|
],
|
||||||
monitor_queue=ContainerType.readonly_inputs,
|
monitor_queue=ContainerType.readonly_inputs,
|
||||||
),
|
),
|
||||||
|
TaskType.dotnet_coverage: TaskDefinition(
|
||||||
|
features=[
|
||||||
|
TaskFeature.target_exe,
|
||||||
|
TaskFeature.target_env,
|
||||||
|
TaskFeature.target_options,
|
||||||
|
TaskFeature.target_timeout,
|
||||||
|
TaskFeature.coverage_filter,
|
||||||
|
TaskFeature.target_must_use_input,
|
||||||
|
],
|
||||||
|
vm=VmDefinition(compare=Compare.Equal, value=1),
|
||||||
|
containers=[
|
||||||
|
ContainerDefinition(
|
||||||
|
type=ContainerType.setup,
|
||||||
|
compare=Compare.Equal,
|
||||||
|
value=1,
|
||||||
|
permissions=[ContainerPermission.Read, ContainerPermission.List],
|
||||||
|
),
|
||||||
|
ContainerDefinition(
|
||||||
|
type=ContainerType.readonly_inputs,
|
||||||
|
compare=Compare.AtLeast,
|
||||||
|
value=1,
|
||||||
|
permissions=[ContainerPermission.Read, ContainerPermission.List],
|
||||||
|
),
|
||||||
|
ContainerDefinition(
|
||||||
|
type=ContainerType.coverage,
|
||||||
|
compare=Compare.Equal,
|
||||||
|
value=1,
|
||||||
|
permissions=[
|
||||||
|
ContainerPermission.List,
|
||||||
|
ContainerPermission.Read,
|
||||||
|
ContainerPermission.Write,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
ContainerDefinition(
|
||||||
|
type=ContainerType.tools,
|
||||||
|
compare=Compare.Equal,
|
||||||
|
value=1,
|
||||||
|
permissions=[ContainerPermission.Read, ContainerPermission.List],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
monitor_queue=ContainerType.readonly_inputs,
|
||||||
|
),
|
||||||
|
TaskType.dotnet_crash_report: TaskDefinition(
|
||||||
|
features=[
|
||||||
|
TaskFeature.target_exe,
|
||||||
|
TaskFeature.target_env,
|
||||||
|
TaskFeature.target_options,
|
||||||
|
TaskFeature.target_timeout,
|
||||||
|
TaskFeature.check_asan_log,
|
||||||
|
TaskFeature.check_debugger,
|
||||||
|
TaskFeature.check_retry_count,
|
||||||
|
TaskFeature.minimized_stack_depth,
|
||||||
|
],
|
||||||
|
vm=VmDefinition(compare=Compare.AtLeast, value=1),
|
||||||
|
containers=[
|
||||||
|
ContainerDefinition(
|
||||||
|
type=ContainerType.setup,
|
||||||
|
compare=Compare.Equal,
|
||||||
|
value=1,
|
||||||
|
permissions=[ContainerPermission.Read, ContainerPermission.List],
|
||||||
|
),
|
||||||
|
ContainerDefinition(
|
||||||
|
type=ContainerType.crashes,
|
||||||
|
compare=Compare.Equal,
|
||||||
|
value=1,
|
||||||
|
permissions=[ContainerPermission.Read, ContainerPermission.List],
|
||||||
|
),
|
||||||
|
ContainerDefinition(
|
||||||
|
type=ContainerType.reports,
|
||||||
|
compare=Compare.AtMost,
|
||||||
|
value=1,
|
||||||
|
permissions=[ContainerPermission.Write],
|
||||||
|
),
|
||||||
|
ContainerDefinition(
|
||||||
|
type=ContainerType.unique_reports,
|
||||||
|
compare=Compare.AtMost,
|
||||||
|
value=1,
|
||||||
|
permissions=[ContainerPermission.Write],
|
||||||
|
),
|
||||||
|
ContainerDefinition(
|
||||||
|
type=ContainerType.no_repro,
|
||||||
|
compare=Compare.AtMost,
|
||||||
|
value=1,
|
||||||
|
permissions=[ContainerPermission.Write],
|
||||||
|
),
|
||||||
|
ContainerDefinition(
|
||||||
|
type=ContainerType.tools,
|
||||||
|
compare=Compare.Equal,
|
||||||
|
value=1,
|
||||||
|
permissions=[ContainerPermission.Read, ContainerPermission.List],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
monitor_queue=ContainerType.crashes,
|
||||||
|
),
|
||||||
|
TaskType.libfuzzer_dotnet_fuzz: TaskDefinition(
|
||||||
|
features=[
|
||||||
|
TaskFeature.target_exe,
|
||||||
|
TaskFeature.target_env,
|
||||||
|
TaskFeature.target_options,
|
||||||
|
TaskFeature.target_workers,
|
||||||
|
TaskFeature.ensemble_sync_delay,
|
||||||
|
TaskFeature.check_fuzzer_help,
|
||||||
|
TaskFeature.expect_crash_on_failure,
|
||||||
|
TaskFeature.target_assembly,
|
||||||
|
TaskFeature.target_class,
|
||||||
|
TaskFeature.target_method,
|
||||||
|
],
|
||||||
|
vm=VmDefinition(compare=Compare.AtLeast, value=1),
|
||||||
|
containers=[
|
||||||
|
ContainerDefinition(
|
||||||
|
type=ContainerType.setup,
|
||||||
|
compare=Compare.Equal,
|
||||||
|
value=1,
|
||||||
|
permissions=[ContainerPermission.Read, ContainerPermission.List],
|
||||||
|
),
|
||||||
|
ContainerDefinition(
|
||||||
|
type=ContainerType.crashes,
|
||||||
|
compare=Compare.Equal,
|
||||||
|
value=1,
|
||||||
|
permissions=[ContainerPermission.Write],
|
||||||
|
),
|
||||||
|
ContainerDefinition(
|
||||||
|
type=ContainerType.inputs,
|
||||||
|
compare=Compare.Equal,
|
||||||
|
value=1,
|
||||||
|
permissions=[
|
||||||
|
ContainerPermission.Write,
|
||||||
|
ContainerPermission.Read,
|
||||||
|
ContainerPermission.List,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
ContainerDefinition(
|
||||||
|
type=ContainerType.readonly_inputs,
|
||||||
|
compare=Compare.AtLeast,
|
||||||
|
value=0,
|
||||||
|
permissions=[ContainerPermission.Read, ContainerPermission.List],
|
||||||
|
),
|
||||||
|
ContainerDefinition(
|
||||||
|
type=ContainerType.tools,
|
||||||
|
compare=Compare.Equal,
|
||||||
|
value=1,
|
||||||
|
permissions=[ContainerPermission.Read, ContainerPermission.List],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
monitor_queue=None,
|
||||||
|
),
|
||||||
TaskType.generic_analysis: TaskDefinition(
|
TaskType.generic_analysis: TaskDefinition(
|
||||||
features=[
|
features=[
|
||||||
TaskFeature.target_exe,
|
TaskFeature.target_exe,
|
||||||
@ -558,40 +704,4 @@ TASK_DEFINITIONS = {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
TaskType.dotnet_coverage: TaskDefinition(
|
|
||||||
features=[
|
|
||||||
TaskFeature.target_exe,
|
|
||||||
TaskFeature.target_env,
|
|
||||||
TaskFeature.target_options,
|
|
||||||
TaskFeature.target_timeout,
|
|
||||||
TaskFeature.coverage_filter,
|
|
||||||
TaskFeature.target_must_use_input,
|
|
||||||
],
|
|
||||||
vm=VmDefinition(compare=Compare.Equal, value=1),
|
|
||||||
containers=[
|
|
||||||
ContainerDefinition(
|
|
||||||
type=ContainerType.setup,
|
|
||||||
compare=Compare.Equal,
|
|
||||||
value=1,
|
|
||||||
permissions=[ContainerPermission.Read, ContainerPermission.List],
|
|
||||||
),
|
|
||||||
ContainerDefinition(
|
|
||||||
type=ContainerType.readonly_inputs,
|
|
||||||
compare=Compare.AtLeast,
|
|
||||||
value=1,
|
|
||||||
permissions=[ContainerPermission.Read, ContainerPermission.List],
|
|
||||||
),
|
|
||||||
ContainerDefinition(
|
|
||||||
type=ContainerType.coverage,
|
|
||||||
compare=Compare.Equal,
|
|
||||||
value=1,
|
|
||||||
permissions=[
|
|
||||||
ContainerPermission.List,
|
|
||||||
ContainerPermission.Read,
|
|
||||||
ContainerPermission.Write,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
monitor_queue=ContainerType.readonly_inputs,
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ $SHARPFUZZ_REPO = 'https://github.com/Metalnem/sharpfuzz'
|
|||||||
$SHARPFUZZ_COMMIT = 'v2.0.0'
|
$SHARPFUZZ_COMMIT = 'v2.0.0'
|
||||||
|
|
||||||
$LIBFUZZER_DOTNET_REPO = 'https://github.com/Metalnem/libfuzzer-dotnet'
|
$LIBFUZZER_DOTNET_REPO = 'https://github.com/Metalnem/libfuzzer-dotnet'
|
||||||
$LIBFUZZER_DOTNET_COMMIT = '55d84f84b3540c864371e855c2a5ecb728865d97'
|
$LIBFUZZER_DOTNET_COMMIT = 'ed148633f8df078cb2b0ba0ca30166aa72f1de90'
|
||||||
|
|
||||||
# Script below assumes an absolute path.
|
# Script below assumes an absolute path.
|
||||||
$ARTIFACTS = "${env:GITHUB_WORKSPACE}/artifacts/third-party/dotnet-fuzzing-windows"
|
$ARTIFACTS = "${env:GITHUB_WORKSPACE}/artifacts/third-party/dotnet-fuzzing-windows"
|
||||||
@ -20,12 +20,12 @@ mkdir $ARTIFACTS/sharpfuzz
|
|||||||
git clone $SHARPFUZZ_REPO sharpfuzz
|
git clone $SHARPFUZZ_REPO sharpfuzz
|
||||||
pushd sharpfuzz
|
pushd sharpfuzz
|
||||||
git checkout $SHARPFUZZ_COMMIT
|
git checkout $SHARPFUZZ_COMMIT
|
||||||
dotnet publish src/SharpFuzz.CommandLine -f net6.0 -c Release -o $ARTIFACTS/sharpfuzz --sc -r win10-x64
|
dotnet publish src/SharpFuzz.CommandLine -f net6.0 -c Release -o $ARTIFACTS/sharpfuzz --self-contained -r win10-x64
|
||||||
popd
|
popd
|
||||||
|
|
||||||
# Build SharpFuzz and our dynamic loader harness for `libfuzzer-dotnet`.
|
# Build SharpFuzz and our dynamic loader harness for `libfuzzer-dotnet`.
|
||||||
pushd src/agent/LibFuzzerDotnetLoader
|
pushd src/agent/LibFuzzerDotnetLoader
|
||||||
dotnet publish . -c Release -o $ARTIFACTS/LibFuzzerDotnetLoader --sc -r win10-x64 -p:PublishSingleFile=true
|
dotnet publish . -c Release -o $ARTIFACTS/LibFuzzerDotnetLoader --sc -r win10-x64
|
||||||
popd
|
popd
|
||||||
|
|
||||||
# Build `libfuzzer-dotnet`.
|
# Build `libfuzzer-dotnet`.
|
||||||
|
@ -8,7 +8,7 @@ export SHARPFUZZ_REPO='https://github.com/Metalnem/sharpfuzz'
|
|||||||
export SHARPFUZZ_COMMIT='v2.0.0'
|
export SHARPFUZZ_COMMIT='v2.0.0'
|
||||||
|
|
||||||
export LIBFUZZER_DOTNET_REPO='https://github.com/Metalnem/libfuzzer-dotnet'
|
export LIBFUZZER_DOTNET_REPO='https://github.com/Metalnem/libfuzzer-dotnet'
|
||||||
export LIBFUZZER_DOTNET_COMMIT='55d84f84b3540c864371e855c2a5ecb728865d97'
|
export LIBFUZZER_DOTNET_COMMIT='ed148633f8df078cb2b0ba0ca30166aa72f1de90'
|
||||||
|
|
||||||
# Script below assumes an absolute path.
|
# Script below assumes an absolute path.
|
||||||
export ARTIFACTS="${GITHUB_WORKSPACE}/artifacts/third-party/dotnet-fuzzing-linux"
|
export ARTIFACTS="${GITHUB_WORKSPACE}/artifacts/third-party/dotnet-fuzzing-linux"
|
||||||
@ -29,12 +29,12 @@ sudo apt-get install -y dotnet-sdk-6.0
|
|||||||
git clone $SHARPFUZZ_REPO sharpfuzz
|
git clone $SHARPFUZZ_REPO sharpfuzz
|
||||||
pushd sharpfuzz
|
pushd sharpfuzz
|
||||||
git checkout $SHARPFUZZ_COMMIT
|
git checkout $SHARPFUZZ_COMMIT
|
||||||
dotnet publish src/SharpFuzz.CommandLine -f net6.0 -c Release -o $ARTIFACTS/sharpfuzz --sc -r linux-x64
|
dotnet publish src/SharpFuzz.CommandLine -f net6.0 -c Release -o $ARTIFACTS/sharpfuzz --self-contained -r linux-x64
|
||||||
popd
|
popd
|
||||||
|
|
||||||
# Build SharpFuzz and our dynamic loader harness for `libfuzzer-dotnet`.
|
# Build SharpFuzz and our dynamic loader harness for `libfuzzer-dotnet`.
|
||||||
pushd src/agent/LibFuzzerDotnetLoader
|
pushd src/agent/LibFuzzerDotnetLoader
|
||||||
dotnet publish . -c Release -o $ARTIFACTS/LibFuzzerDotnetLoader --sc -r linux-x64 -p:PublishSingleFile=true
|
dotnet publish . -c Release -o $ARTIFACTS/LibFuzzerDotnetLoader --sc -r linux-x64
|
||||||
popd
|
popd
|
||||||
|
|
||||||
# Build `libfuzzer-dotnet`.
|
# Build `libfuzzer-dotnet`.
|
||||||
|
@ -902,6 +902,9 @@ class Tasks(Endpoint):
|
|||||||
target_options_merge: bool = False,
|
target_options_merge: bool = False,
|
||||||
target_timeout: Optional[int] = None,
|
target_timeout: Optional[int] = None,
|
||||||
target_workers: Optional[int] = None,
|
target_workers: Optional[int] = None,
|
||||||
|
target_assembly: Optional[str] = None,
|
||||||
|
target_class: Optional[str] = None,
|
||||||
|
target_method: Optional[str] = None,
|
||||||
vm_count: int = 1,
|
vm_count: int = 1,
|
||||||
preserve_existing_outputs: bool = False,
|
preserve_existing_outputs: bool = False,
|
||||||
colocate: bool = False,
|
colocate: bool = False,
|
||||||
@ -975,6 +978,9 @@ class Tasks(Endpoint):
|
|||||||
target_options_merge=target_options_merge,
|
target_options_merge=target_options_merge,
|
||||||
target_timeout=target_timeout,
|
target_timeout=target_timeout,
|
||||||
target_workers=target_workers,
|
target_workers=target_workers,
|
||||||
|
target_assembly=target_assembly,
|
||||||
|
target_class=target_class,
|
||||||
|
target_method=target_method,
|
||||||
type=task_type,
|
type=task_type,
|
||||||
wait_for_files=task_wait_for_files,
|
wait_for_files=task_wait_for_files,
|
||||||
report_list=report_list,
|
report_list=report_list,
|
||||||
|
@ -18,6 +18,12 @@ from . import JobHelper
|
|||||||
|
|
||||||
LIBFUZZER_MAGIC_STRING = b"ERROR: libFuzzer"
|
LIBFUZZER_MAGIC_STRING = b"ERROR: libFuzzer"
|
||||||
|
|
||||||
|
# The loader DLL is managed, but links platform-specific code. Task VMs must pull the
|
||||||
|
# tools container that matches their platform (which will contain the correct DLL).
|
||||||
|
LIBFUZZER_DOTNET_LOADER_PATH = (
|
||||||
|
"{tools_dir}/LibFuzzerDotnetLoader/LibFuzzerDotnetLoader.dll"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class QemuArch(Enum):
|
class QemuArch(Enum):
|
||||||
aarch64 = "aarch64"
|
aarch64 = "aarch64"
|
||||||
@ -536,7 +542,7 @@ class Libfuzzer(Command):
|
|||||||
|
|
||||||
pool = self.onefuzz.pools.get(pool_name)
|
pool = self.onefuzz.pools.get(pool_name)
|
||||||
if pool.os != OS.linux:
|
if pool.os != OS.linux:
|
||||||
raise Exception("libfuzzer-dotnet jobs are only compatable on linux")
|
raise Exception("libfuzzer-dotnet jobs are only compatible on linux")
|
||||||
|
|
||||||
target_exe = File(os.path.join(setup_dir, harness))
|
target_exe = File(os.path.join(setup_dir, harness))
|
||||||
if not os.path.exists(target_exe):
|
if not os.path.exists(target_exe):
|
||||||
@ -544,7 +550,7 @@ class Libfuzzer(Command):
|
|||||||
|
|
||||||
assembly_path = os.path.join(setup_dir, target_harness)
|
assembly_path = os.path.join(setup_dir, target_harness)
|
||||||
if not os.path.exists(assembly_path):
|
if not os.path.exists(assembly_path):
|
||||||
raise Exception(f"missing assembly: {assembly_path}")
|
raise Exception(f"missing assembly: {target_harness}")
|
||||||
|
|
||||||
self._check_is_libfuzzer(target_exe)
|
self._check_is_libfuzzer(target_exe)
|
||||||
if target_options is None:
|
if target_options is None:
|
||||||
@ -622,6 +628,207 @@ class Libfuzzer(Command):
|
|||||||
helper.wait()
|
helper.wait()
|
||||||
return helper.job
|
return helper.job
|
||||||
|
|
||||||
|
def dotnet_dll(
|
||||||
|
self,
|
||||||
|
project: str,
|
||||||
|
name: str,
|
||||||
|
build: str,
|
||||||
|
pool_name: PoolName,
|
||||||
|
*,
|
||||||
|
setup_dir: Directory,
|
||||||
|
target_dll: File,
|
||||||
|
target_class: str,
|
||||||
|
target_method: str,
|
||||||
|
vm_count: int = 1,
|
||||||
|
inputs: Optional[Directory] = None,
|
||||||
|
reboot_after_setup: bool = False,
|
||||||
|
duration: int = 24,
|
||||||
|
target_workers: Optional[int] = None,
|
||||||
|
fuzzing_target_options: Optional[List[str]] = None,
|
||||||
|
target_env: Optional[Dict[str, str]] = None,
|
||||||
|
target_timeout: Optional[int] = None,
|
||||||
|
check_retry_count: Optional[int] = None,
|
||||||
|
tags: Optional[Dict[str, str]] = None,
|
||||||
|
wait_for_running: bool = False,
|
||||||
|
wait_for_files: Optional[List[ContainerType]] = None,
|
||||||
|
existing_inputs: Optional[Container] = None,
|
||||||
|
debug: Optional[List[TaskDebugFlag]] = None,
|
||||||
|
ensemble_sync_delay: Optional[int] = None,
|
||||||
|
colocate_all_tasks: bool = False,
|
||||||
|
colocate_secondary_tasks: bool = True,
|
||||||
|
expect_crash_on_failure: bool = False,
|
||||||
|
) -> Optional[Job]:
|
||||||
|
pool = self.onefuzz.pools.get(pool_name)
|
||||||
|
|
||||||
|
# We _must_ proactively specify the OS based on pool.
|
||||||
|
#
|
||||||
|
# This is because managed DLLs are always (Windows-native) PE files, so the job
|
||||||
|
# helper's platform guess (based on the file type of `target_exe`) will always
|
||||||
|
# evaluate to `OS.windows`. In the case of true Linux `libfuzzer dotnet_dll` jobs,
|
||||||
|
# this leads to a client- side validation error when the helper checks the nominal
|
||||||
|
# target OS against the pool OS.
|
||||||
|
platform = pool.os
|
||||||
|
|
||||||
|
helper = JobHelper(
|
||||||
|
self.onefuzz,
|
||||||
|
self.logger,
|
||||||
|
project,
|
||||||
|
name,
|
||||||
|
build,
|
||||||
|
duration,
|
||||||
|
pool_name=pool_name,
|
||||||
|
target_exe=target_dll,
|
||||||
|
platform=platform,
|
||||||
|
)
|
||||||
|
|
||||||
|
target_dll_blob_name = helper.setup_relative_blob_name(target_dll, setup_dir)
|
||||||
|
|
||||||
|
target_env = target_env or {}
|
||||||
|
|
||||||
|
# Set target environment variables for `LibFuzzerDotnetLoader`.
|
||||||
|
target_env["LIBFUZZER_DOTNET_TARGET_ASSEMBLY"] = (
|
||||||
|
"{setup_dir}/" + target_dll_blob_name
|
||||||
|
)
|
||||||
|
target_env["LIBFUZZER_DOTNET_TARGET_CLASS"] = target_class
|
||||||
|
target_env["LIBFUZZER_DOTNET_TARGET_METHOD"] = target_method
|
||||||
|
|
||||||
|
helper.add_tags(tags)
|
||||||
|
helper.define_containers(
|
||||||
|
ContainerType.setup,
|
||||||
|
ContainerType.inputs,
|
||||||
|
ContainerType.crashes,
|
||||||
|
ContainerType.coverage,
|
||||||
|
ContainerType.reports,
|
||||||
|
ContainerType.unique_reports,
|
||||||
|
ContainerType.no_repro,
|
||||||
|
)
|
||||||
|
|
||||||
|
containers = helper.containers
|
||||||
|
|
||||||
|
if existing_inputs:
|
||||||
|
self.onefuzz.containers.get(existing_inputs)
|
||||||
|
helper.containers[ContainerType.inputs] = existing_inputs
|
||||||
|
else:
|
||||||
|
helper.define_containers(ContainerType.inputs)
|
||||||
|
|
||||||
|
# Assumes that `libfuzzer-dotnet` and supporting tools were uploaded upon deployment.
|
||||||
|
fuzzer_tools_container = Container(
|
||||||
|
"dotnet-fuzzing-linux" if platform == OS.linux else "dotnet-fuzzing-windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
fuzzer_containers = [
|
||||||
|
(ContainerType.setup, containers[ContainerType.setup]),
|
||||||
|
(ContainerType.crashes, containers[ContainerType.crashes]),
|
||||||
|
(ContainerType.inputs, containers[ContainerType.inputs]),
|
||||||
|
(ContainerType.tools, fuzzer_tools_container),
|
||||||
|
]
|
||||||
|
|
||||||
|
helper.create_containers()
|
||||||
|
|
||||||
|
helper.upload_setup(setup_dir, target_dll)
|
||||||
|
|
||||||
|
if inputs:
|
||||||
|
helper.upload_inputs(inputs)
|
||||||
|
|
||||||
|
helper.wait_on(wait_for_files, wait_for_running)
|
||||||
|
|
||||||
|
fuzzer_task = self.onefuzz.tasks.create(
|
||||||
|
helper.job.job_id,
|
||||||
|
TaskType.libfuzzer_dotnet_fuzz,
|
||||||
|
target_dll_blob_name, # Not used
|
||||||
|
fuzzer_containers,
|
||||||
|
pool_name=pool_name,
|
||||||
|
reboot_after_setup=reboot_after_setup,
|
||||||
|
duration=duration,
|
||||||
|
vm_count=vm_count,
|
||||||
|
target_options=fuzzing_target_options,
|
||||||
|
target_env=target_env,
|
||||||
|
target_assembly=target_dll_blob_name,
|
||||||
|
target_class=target_class,
|
||||||
|
target_method=target_method,
|
||||||
|
target_workers=target_workers,
|
||||||
|
tags=tags,
|
||||||
|
debug=debug,
|
||||||
|
ensemble_sync_delay=ensemble_sync_delay,
|
||||||
|
expect_crash_on_failure=expect_crash_on_failure,
|
||||||
|
check_fuzzer_help=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ensure the fuzzing task starts before we schedule the coverage and
|
||||||
|
# crash reporting tasks (which are useless without it).
|
||||||
|
prereq_tasks = [fuzzer_task.task_id]
|
||||||
|
|
||||||
|
# Target options for the .NET harness produced by SharpFuzz, when _not_
|
||||||
|
# invoked as a child process of `libfuzzer-dotnet`. This harness has a
|
||||||
|
# `main()` function with one argument: the path to an input test case.
|
||||||
|
sharpfuzz_harness_target_options = ["{input}"]
|
||||||
|
|
||||||
|
# Set the path to the `LibFuzzerDotnetLoader` DLL.
|
||||||
|
#
|
||||||
|
# This provides a `main()` function that dynamically loads a target DLL
|
||||||
|
# passed via environment variables. This is assumed to be installed on
|
||||||
|
# the VMs.
|
||||||
|
libfuzzer_dotnet_loader_dll = LIBFUZZER_DOTNET_LOADER_PATH
|
||||||
|
|
||||||
|
coverage_containers = [
|
||||||
|
(ContainerType.setup, containers[ContainerType.setup]),
|
||||||
|
(ContainerType.coverage, containers[ContainerType.coverage]),
|
||||||
|
(ContainerType.readonly_inputs, containers[ContainerType.inputs]),
|
||||||
|
(ContainerType.tools, fuzzer_tools_container),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.logger.info("creating `dotnet_coverage` task")
|
||||||
|
self.onefuzz.tasks.create(
|
||||||
|
helper.job.job_id,
|
||||||
|
TaskType.dotnet_coverage,
|
||||||
|
libfuzzer_dotnet_loader_dll,
|
||||||
|
coverage_containers,
|
||||||
|
pool_name=pool_name,
|
||||||
|
duration=duration,
|
||||||
|
vm_count=1,
|
||||||
|
reboot_after_setup=reboot_after_setup,
|
||||||
|
target_options=sharpfuzz_harness_target_options,
|
||||||
|
target_env=target_env,
|
||||||
|
target_timeout=target_timeout,
|
||||||
|
tags=tags,
|
||||||
|
prereq_tasks=prereq_tasks,
|
||||||
|
debug=debug,
|
||||||
|
colocate=colocate_all_tasks or colocate_secondary_tasks,
|
||||||
|
)
|
||||||
|
|
||||||
|
report_containers = [
|
||||||
|
(ContainerType.setup, containers[ContainerType.setup]),
|
||||||
|
(ContainerType.crashes, containers[ContainerType.crashes]),
|
||||||
|
(ContainerType.reports, containers[ContainerType.reports]),
|
||||||
|
(ContainerType.unique_reports, containers[ContainerType.unique_reports]),
|
||||||
|
(ContainerType.no_repro, containers[ContainerType.no_repro]),
|
||||||
|
(ContainerType.tools, fuzzer_tools_container),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.logger.info("creating `dotnet_crash_report` task")
|
||||||
|
self.onefuzz.tasks.create(
|
||||||
|
helper.job.job_id,
|
||||||
|
TaskType.dotnet_crash_report,
|
||||||
|
libfuzzer_dotnet_loader_dll,
|
||||||
|
report_containers,
|
||||||
|
pool_name=pool_name,
|
||||||
|
duration=duration,
|
||||||
|
vm_count=1,
|
||||||
|
reboot_after_setup=reboot_after_setup,
|
||||||
|
target_options=sharpfuzz_harness_target_options,
|
||||||
|
target_env=target_env,
|
||||||
|
tags=tags,
|
||||||
|
prereq_tasks=prereq_tasks,
|
||||||
|
target_timeout=target_timeout,
|
||||||
|
check_retry_count=check_retry_count,
|
||||||
|
debug=debug,
|
||||||
|
colocate=colocate_all_tasks or colocate_secondary_tasks,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.logger.info("done creating tasks")
|
||||||
|
helper.wait()
|
||||||
|
return helper.job
|
||||||
|
|
||||||
def qemu_user(
|
def qemu_user(
|
||||||
self,
|
self,
|
||||||
project: str,
|
project: str,
|
||||||
|
@ -52,6 +52,7 @@ class TaskTestState(Enum):
|
|||||||
class TemplateType(Enum):
|
class TemplateType(Enum):
|
||||||
libfuzzer = "libfuzzer"
|
libfuzzer = "libfuzzer"
|
||||||
libfuzzer_dotnet = "libfuzzer_dotnet"
|
libfuzzer_dotnet = "libfuzzer_dotnet"
|
||||||
|
libfuzzer_dotnet_dll = "libfuzzer_dotnet_dll"
|
||||||
libfuzzer_qemu_user = "libfuzzer_qemu_user"
|
libfuzzer_qemu_user = "libfuzzer_qemu_user"
|
||||||
afl = "afl"
|
afl = "afl"
|
||||||
radamsa = "radamsa"
|
radamsa = "radamsa"
|
||||||
@ -76,6 +77,9 @@ class Integration(BaseModel):
|
|||||||
test_repro: Optional[bool] = Field(default=True)
|
test_repro: Optional[bool] = Field(default=True)
|
||||||
target_options: Optional[List[str]]
|
target_options: Optional[List[str]]
|
||||||
inject_fake_regression: bool = Field(default=False)
|
inject_fake_regression: bool = Field(default=False)
|
||||||
|
target_class: Optional[str]
|
||||||
|
target_method: Optional[str]
|
||||||
|
setup_dir: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
TARGETS: Dict[str, Integration] = {
|
TARGETS: Dict[str, Integration] = {
|
||||||
@ -148,6 +152,23 @@ TARGETS: Dict[str, Integration] = {
|
|||||||
wait_for_files={ContainerType.inputs: 2, ContainerType.crashes: 1},
|
wait_for_files={ContainerType.inputs: 2, ContainerType.crashes: 1},
|
||||||
test_repro=False,
|
test_repro=False,
|
||||||
),
|
),
|
||||||
|
"linux-libfuzzer-dotnet-dll": Integration(
|
||||||
|
template=TemplateType.libfuzzer_dotnet_dll,
|
||||||
|
os=OS.linux,
|
||||||
|
setup_dir="GoodBadDotnet",
|
||||||
|
target_exe="GoodBadDotnet/GoodBad.dll",
|
||||||
|
target_options=["-max_len=4", "-only_ascii=1", "-seed=1"],
|
||||||
|
target_class="GoodBad.Fuzzer",
|
||||||
|
target_method="TestInput",
|
||||||
|
use_setup=True,
|
||||||
|
wait_for_files={
|
||||||
|
ContainerType.inputs: 2,
|
||||||
|
ContainerType.coverage: 1,
|
||||||
|
ContainerType.crashes: 1,
|
||||||
|
ContainerType.unique_reports: 1,
|
||||||
|
},
|
||||||
|
test_repro=False,
|
||||||
|
),
|
||||||
"linux-libfuzzer-aarch64-crosscompile": Integration(
|
"linux-libfuzzer-aarch64-crosscompile": Integration(
|
||||||
template=TemplateType.libfuzzer_qemu_user,
|
template=TemplateType.libfuzzer_qemu_user,
|
||||||
os=OS.linux,
|
os=OS.linux,
|
||||||
@ -216,6 +237,23 @@ TARGETS: Dict[str, Integration] = {
|
|||||||
},
|
},
|
||||||
use_setup=True,
|
use_setup=True,
|
||||||
),
|
),
|
||||||
|
"windows-libfuzzer-dotnet-dll": Integration(
|
||||||
|
template=TemplateType.libfuzzer_dotnet_dll,
|
||||||
|
os=OS.windows,
|
||||||
|
setup_dir="GoodBadDotnet",
|
||||||
|
target_exe="GoodBadDotnet/GoodBad.dll",
|
||||||
|
target_options=["-max_len=4", "-only_ascii=1", "-seed=1"],
|
||||||
|
target_class="GoodBad.Fuzzer",
|
||||||
|
target_method="TestInput",
|
||||||
|
use_setup=True,
|
||||||
|
wait_for_files={
|
||||||
|
ContainerType.inputs: 2,
|
||||||
|
ContainerType.coverage: 1,
|
||||||
|
ContainerType.crashes: 1,
|
||||||
|
ContainerType.unique_reports: 1,
|
||||||
|
},
|
||||||
|
test_repro=False,
|
||||||
|
),
|
||||||
"windows-trivial-crash": Integration(
|
"windows-trivial-crash": Integration(
|
||||||
template=TemplateType.radamsa,
|
template=TemplateType.radamsa,
|
||||||
os=OS.windows,
|
os=OS.windows,
|
||||||
@ -315,7 +353,11 @@ class TestOnefuzz:
|
|||||||
|
|
||||||
self.logger.info("launching: %s", target)
|
self.logger.info("launching: %s", target)
|
||||||
|
|
||||||
|
if config.setup_dir is None:
|
||||||
setup = Directory(os.path.join(path, target)) if config.use_setup else None
|
setup = Directory(os.path.join(path, target)) if config.use_setup else None
|
||||||
|
else:
|
||||||
|
setup = config.setup_dir
|
||||||
|
|
||||||
target_exe = File(os.path.join(path, target, config.target_exe))
|
target_exe = File(os.path.join(path, target, config.target_exe))
|
||||||
inputs = (
|
inputs = (
|
||||||
Directory(os.path.join(path, target, config.inputs))
|
Directory(os.path.join(path, target, config.inputs))
|
||||||
@ -356,6 +398,28 @@ class TestOnefuzz:
|
|||||||
vm_count=1,
|
vm_count=1,
|
||||||
target_options=config.target_options,
|
target_options=config.target_options,
|
||||||
)
|
)
|
||||||
|
elif config.template == TemplateType.libfuzzer_dotnet_dll:
|
||||||
|
if setup is None:
|
||||||
|
raise Exception("setup required for libfuzzer_dotnet_dll")
|
||||||
|
if config.target_class is None:
|
||||||
|
raise Exception("target_class required for libfuzzer_dotnet_dll")
|
||||||
|
if config.target_method is None:
|
||||||
|
raise Exception("target_method required for libfuzzer_dotnet_dll")
|
||||||
|
|
||||||
|
job = self.of.template.libfuzzer.dotnet_dll(
|
||||||
|
self.project,
|
||||||
|
target,
|
||||||
|
BUILD,
|
||||||
|
pools[config.os].name,
|
||||||
|
target_dll=config.target_exe,
|
||||||
|
inputs=inputs,
|
||||||
|
setup_dir=setup,
|
||||||
|
duration=duration,
|
||||||
|
vm_count=1,
|
||||||
|
fuzzing_target_options=config.target_options,
|
||||||
|
target_class=config.target_class,
|
||||||
|
target_method=config.target_method,
|
||||||
|
)
|
||||||
elif config.template == TemplateType.libfuzzer_qemu_user:
|
elif config.template == TemplateType.libfuzzer_qemu_user:
|
||||||
job = self.of.template.libfuzzer.qemu_user(
|
job = self.of.template.libfuzzer.qemu_user(
|
||||||
self.project,
|
self.project,
|
||||||
|
@ -82,6 +82,9 @@ class TaskFeature(Enum):
|
|||||||
minimized_stack_depth = "minimized_stack_depth"
|
minimized_stack_depth = "minimized_stack_depth"
|
||||||
coverage_filter = "coverage_filter"
|
coverage_filter = "coverage_filter"
|
||||||
target_must_use_input = "target_must_use_input"
|
target_must_use_input = "target_must_use_input"
|
||||||
|
target_assembly = "target_assembly"
|
||||||
|
target_class = "target_class"
|
||||||
|
target_method = "target_method"
|
||||||
|
|
||||||
|
|
||||||
# Permissions for an Azure Blob Storage Container.
|
# Permissions for an Azure Blob Storage Container.
|
||||||
@ -150,6 +153,9 @@ class TaskState(Enum):
|
|||||||
|
|
||||||
class TaskType(Enum):
|
class TaskType(Enum):
|
||||||
coverage = "coverage"
|
coverage = "coverage"
|
||||||
|
dotnet_coverage = "dotnet_coverage"
|
||||||
|
dotnet_crash_report = "dotnet_crash_report"
|
||||||
|
libfuzzer_dotnet_fuzz = "libfuzzer_dotnet_fuzz"
|
||||||
libfuzzer_fuzz = "libfuzzer_fuzz"
|
libfuzzer_fuzz = "libfuzzer_fuzz"
|
||||||
|
|
||||||
# Deprecated, kept for deserialization of old task data.
|
# Deprecated, kept for deserialization of old task data.
|
||||||
@ -165,8 +171,6 @@ class TaskType(Enum):
|
|||||||
generic_crash_report = "generic_crash_report"
|
generic_crash_report = "generic_crash_report"
|
||||||
generic_regression = "generic_regression"
|
generic_regression = "generic_regression"
|
||||||
|
|
||||||
dotnet_coverage = "dotnet_coverage"
|
|
||||||
|
|
||||||
|
|
||||||
class VmState(Enum):
|
class VmState(Enum):
|
||||||
init = "init"
|
init = "init"
|
||||||
|
@ -163,6 +163,9 @@ class TaskDetails(BaseModel):
|
|||||||
report_list: Optional[List[str]]
|
report_list: Optional[List[str]]
|
||||||
minimized_stack_depth: Optional[int]
|
minimized_stack_depth: Optional[int]
|
||||||
coverage_filter: Optional[str]
|
coverage_filter: Optional[str]
|
||||||
|
target_assembly: Optional[str]
|
||||||
|
target_class: Optional[str]
|
||||||
|
target_method: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
class TaskPool(BaseModel):
|
class TaskPool(BaseModel):
|
||||||
@ -378,6 +381,9 @@ class TaskUnitConfig(BaseModel):
|
|||||||
report_list: Optional[List[str]]
|
report_list: Optional[List[str]]
|
||||||
minimized_stack_depth: Optional[int]
|
minimized_stack_depth: Optional[int]
|
||||||
coverage_filter: Optional[str]
|
coverage_filter: Optional[str]
|
||||||
|
target_assembly: Optional[str]
|
||||||
|
target_class: Optional[str]
|
||||||
|
target_method: Optional[str]
|
||||||
|
|
||||||
# from here forwards are Container definitions. These need to be inline
|
# from here forwards are Container definitions. These need to be inline
|
||||||
# with TaskDefinitions and ContainerTypes
|
# with TaskDefinitions and ContainerTypes
|
||||||
|
Reference in New Issue
Block a user