libfuzzer-dotnet integration (#535)

This commit is contained in:
bmc-msft
2021-02-11 17:30:24 -05:00
committed by GitHub
parent 360693e8a4
commit 933fe6850c
10 changed files with 451 additions and 7 deletions

View File

@ -31,7 +31,7 @@ from onefuzz.backend import ContainerWrapper, wait
from onefuzz.cli import execute_api
from onefuzztypes.enums import OS, ContainerType, TaskState, VmState
from onefuzztypes.models import Job, Pool, Repro, Scaleset
from onefuzztypes.primitives import Directory, File
from onefuzztypes.primitives import Container, Directory, File, PoolName, Region
from pydantic import BaseModel, Field
LINUX_POOL = "linux-test"
@ -41,6 +41,7 @@ BUILD = "0"
class TemplateType(Enum):
libfuzzer = "libfuzzer"
libfuzzer_dotnet = "libfuzzer_dotnet"
afl = "afl"
radamsa = "radamsa"
@ -51,6 +52,7 @@ class Integration(BaseModel):
target_exe: str
inputs: Optional[str]
use_setup: bool = Field(default=False)
nested_setup_dir: Optional[str]
wait_for_files: List[ContainerType]
check_asan_log: Optional[bool] = Field(default=False)
disable_check_debugger: Optional[bool] = Field(default=False)
@ -73,6 +75,15 @@ TARGETS: Dict[str, Integration] = {
wait_for_files=[ContainerType.unique_reports, ContainerType.coverage],
reboot_after_setup=True,
),
"linux-libfuzzer-dotnet": Integration(
template=TemplateType.libfuzzer_dotnet,
os=OS.linux,
target_exe="wrapper",
nested_setup_dir="my-fuzzer",
inputs="inputs",
use_setup=True,
wait_for_files=[ContainerType.inputs, ContainerType.crashes],
),
"linux-libfuzzer-rust": Integration(
template=TemplateType.libfuzzer,
os=OS.linux,
@ -159,7 +170,7 @@ class TestOnefuzz:
def setup(
self,
*,
region: Optional[str] = None,
region: Optional[Region] = None,
user_pools: Optional[Dict[str, str]] = None,
) -> None:
for entry in self.os:
@ -169,7 +180,7 @@ class TestOnefuzz:
)
self.pools[entry] = self.of.pools.get(user_pools[entry.name])
else:
name = "pool-%s-%s" % (self.project, entry.name)
name = PoolName("pool-%s-%s" % (self.project, entry.name))
self.logger.info("creating pool: %s:%s", entry.name, name)
self.pools[entry] = self.of.pools.create(name, entry)
self.logger.info("creating scaleset for pool: %s", name)
@ -195,6 +206,9 @@ class TestOnefuzz:
else None
)
if setup and config.nested_setup_dir:
setup = Directory(os.path.join(setup, config.nested_setup_dir))
job: Optional[Job] = None
if config.template == TemplateType.libfuzzer:
job = self.of.template.libfuzzer.basic(
@ -207,7 +221,21 @@ class TestOnefuzz:
setup_dir=setup,
duration=1,
vm_count=1,
reboot_after_setup=config.reboot_after_setup,
reboot_after_setup=config.reboot_after_setup or False,
)
elif config.template == TemplateType.libfuzzer_dotnet:
if setup is None:
raise Exception("setup required for libfuzzer_dotnet")
job = self.of.template.libfuzzer.dotnet(
self.project,
target,
BUILD,
self.pools[config.os].name,
target_harness=config.target_exe,
inputs=inputs,
setup_dir=setup,
duration=1,
vm_count=1,
)
elif config.template == TemplateType.radamsa:
job = self.of.template.radamsa.basic(
@ -362,7 +390,7 @@ class TestOnefuzz:
self.logger.info("checking jobs")
return wait(self.check_jobs_impl)
def get_job_crash(self, job_id: UUID) -> Optional[Tuple[str, str]]:
def get_job_crash(self, job_id: UUID) -> Optional[Tuple[Container, str]]:
# get the crash container for a given job
for task in self.of.tasks.list(job_id=job_id, state=None):
@ -396,6 +424,7 @@ class TestOnefuzz:
self.logger.info("launching repro: %s", self.target_jobs[job_id])
report = self.get_job_crash(job_id)
if report is None:
self.logger.warning("target does not include crash reports: %s", self.target_jobs[job_id])
return
(container, path) = report
self.repros[job_id] = self.of.repro.create(container, path, duration=1)
@ -555,7 +584,7 @@ class Run(Command):
endpoint: Optional[str] = None,
user_pools: Optional[Dict[str, str]] = None,
pool_size: int = 10,
region: Optional[str] = None,
region: Optional[Region] = None,
os_list: List[OS] = [OS.linux, OS.windows],
targets: List[str] = list(TARGETS.keys()),
skip_repro: bool = False,
@ -580,6 +609,7 @@ class Run(Command):
if skip_repro:
self.logger.warning("not testing crash repro")
else:
self.logger.info("launching crash repro tests")
tester.launch_repro()
tester.check_repro()
except Exception as e:

View File

@ -0,0 +1,24 @@
all: check
libfuzzer-dotnet:
mkdir -p my-fuzzer
# direct url to a known-good instance of libfuzzer-dotnet.cc
curl -o libfuzzer-dotnet.cc https://raw.githubusercontent.com/Metalnem/libfuzzer-dotnet/543b170a67bdd39e9ba260fe54bc93c77b877c24/libfuzzer-dotnet.cc
clang -fsanitize=fuzzer libfuzzer-dotnet.cc -o my-fuzzer/libfuzzer-dotnet
rm -f libfuzzer-dotnet.cc
build-harness: libfuzzer-dotnet
dotnet tool install --global SharpFuzz.CommandLine || echo already installed
dotnet publish ./wrapper/wrapper.csproj -c release -o my-fuzzer -r linux-x64
sharpfuzz my-fuzzer/problems.dll || echo already instrumented
check: build-harness
./my-fuzzer/libfuzzer-dotnet --target_path=./my-fuzzer/wrapper -runs=1
fuzz: check
./my-fuzzer/libfuzzer-dotnet --target_path=./my-fuzzer/wrapper
.PHONY: clean
clean:
rm -rf fuzz.exe libfuzzer-dotnet my-fuzzer wrapper/bin wrapper/obj problems/bin problems/obj

View File

@ -0,0 +1 @@
hi

View File

@ -0,0 +1,15 @@
using System;
namespace Problems {
public static class Problems {
public static void Func(ReadOnlySpan<byte> data) {
var count = 0;
if (data.Length < 4) {
return;
}
if (data[0] == 0) { count++; }
if (data[1] == 1) { count++; }
if (data[2] == 2) { count++; }
if (count >= 3) { throw new Exception("this is bad"); }
}
}
}

View File

@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,8 @@
using SharpFuzz;
namespace Wrapper {
public class Program {
public static void Main(string[] args) {
Fuzzer.LibFuzzer.Run(stream => { Problems.Problems.Func(stream); });
}
}
}

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\problems\problems.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SharpFuzz" Version="1.6.1" />
</ItemGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
</Project>