aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/getting-started/continuous_integration.md62
-rw-r--r--infra/cifuzz/actions/build_fuzzers/action.yml4
-rw-r--r--infra/cifuzz/actions/build_fuzzers/build_fuzzers_entrypoint.py22
-rw-r--r--infra/cifuzz/actions/run_fuzzers/action.yml4
-rw-r--r--infra/cifuzz/actions/run_fuzzers/run_fuzzers_entrypoint.py9
-rw-r--r--infra/cifuzz/cifuzz.py72
-rw-r--r--infra/cifuzz/cifuzz_test.py136
-rw-r--r--infra/cifuzz/fuzz_target.py18
-rwxr-xr-xinfra/cifuzz/test_files/out/memory/out/curl_fuzzer_memorybin0 -> 9768680 bytes
-rwxr-xr-xinfra/cifuzz/test_files/out/undefined/out/curl_fuzzer_undefinedbin0 -> 14401312 bytes
10 files changed, 290 insertions, 37 deletions
diff --git a/docs/getting-started/continuous_integration.md b/docs/getting-started/continuous_integration.md
index cc461a5b4..d536ea9be 100644
--- a/docs/getting-started/continuous_integration.md
+++ b/docs/getting-started/continuous_integration.md
@@ -82,6 +82,7 @@ jobs:
### Optional configuration
+#### Configurable Variables
`fuzz-time`: Determines how long CIFuzz spends fuzzing your project in seconds.
The default is 600 seconds. The GitHub Actions max run time is 21600 seconds (6 hours).
@@ -94,6 +95,67 @@ make sure to set the dry-run parameters in both the `Build Fuzzers` and `Run Fuz
limit for broken fuzz targets than OSS-Fuzz's check_build. Most users should
not set this.
+#### Adding Other Sanitizers
+CIFuzz supports address, memory and undefined sanitizers. Address is the default
+sanitizer and will be used for every job in which a sanitizer is not specified.
+To add another sanitizer to your workflow copy the `Fuzzing` job and rename it
+to the sanitizer you want to fuzz with. Then add the sanitizer variable to both
+the `Build Fuzzers` step and the `Run Fuzzers` step. The choices are `'address'`,
+`'memory'`, and `'undefined'`. Once this additional job is configured the CIFuzz
+workflow will run all of the jobs corresponding to each sanitizer simultaneously.
+It is important to note that the `Build Fuzzers` and the `Run Fuzzers` sanitizer
+field needs to be the same. See the following main.yml file for an example.
+
+```yaml
+name: CIFuzz
+on: [pull_request]
+jobs:
+ AddressFuzzing:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Build Fuzzers
+ uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
+ with:
+ oss-fuzz-project-name: 'example'
+ dry-run: false
+ # sanitizer: address
+ - name: Run Fuzzers
+ uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
+ with:
+ oss-fuzz-project-name: 'example'
+ fuzz-seconds: 600
+ dry-run: false
+ # sanitizer: address
+ - name: Upload Crash
+ uses: actions/upload-artifact@v1
+ if: failure()
+ with:
+ name: Address-Artifacts
+ path: ./out/artifacts
+ UndefinedFuzzing:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Build Fuzzers
+ uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
+ with:
+ oss-fuzz-project-name: 'example'
+ dry-run: false
+ sanitizer: 'undefined'
+ - name: Run Fuzzers
+ uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
+ with:
+ oss-fuzz-project-name: 'example'
+ fuzz-seconds: 600
+ dry-run: false
+ sanitizer: 'undefined'
+ - name: Upload Crash
+ uses: actions/upload-artifact@v1
+ if: failure()
+ with:
+ name: Undefined-Artifacts
+ path: ./out/artifacts
+```
+
## Understanding results
The results of CIFuzz can be found in two different places.
diff --git a/infra/cifuzz/actions/build_fuzzers/action.yml b/infra/cifuzz/actions/build_fuzzers/action.yml
index 4c190185c..534f71552 100644
--- a/infra/cifuzz/actions/build_fuzzers/action.yml
+++ b/infra/cifuzz/actions/build_fuzzers/action.yml
@@ -11,6 +11,9 @@ inputs:
allowed-broken-targets-percentage:
description: 'The percentage of broken targets allowed in bad_build_check.'
required: false
+ sanitizer:
+ description: 'The sanitizer to build the fuzzers with.'
+ default: 'address'
runs:
using: 'docker'
image: 'Dockerfile'
@@ -18,3 +21,4 @@ runs:
OSS_FUZZ_PROJECT_NAME: ${{ inputs.oss-fuzz-project-name }}
DRY_RUN: ${{ inputs.dry-run}}
ALLOWED_BROKEN_TARGETS_PERCENTAGE: ${{ inputs.allowed-broken-targets-percentage}}
+ SANITIZER: ${{ inputs.sanitizer }}
diff --git a/infra/cifuzz/actions/build_fuzzers/build_fuzzers_entrypoint.py b/infra/cifuzz/actions/build_fuzzers/build_fuzzers_entrypoint.py
index c2030688e..74cd2d495 100644
--- a/infra/cifuzz/actions/build_fuzzers/build_fuzzers_entrypoint.py
+++ b/infra/cifuzz/actions/build_fuzzers/build_fuzzers_entrypoint.py
@@ -46,6 +46,8 @@ def main():
The path to the file containing the POST payload of the webhook:
https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners#filesystems-on-github-hosted-runners
GITHUB_WORKSPACE: The shared volume directory where input artifacts are.
+ DRY_RUN: If true, no failures will surface.
+ SANITIZER: The sanitizer to use when running fuzzers.
Returns:
0 on success or 1 on Failure.
@@ -55,6 +57,7 @@ def main():
commit_sha = os.environ.get('GITHUB_SHA')
event = os.environ.get('GITHUB_EVENT_NAME')
workspace = os.environ.get('GITHUB_WORKSPACE')
+ sanitizer = os.environ.get('SANITIZER').lower()
# Check if failures should not be reported.
dry_run = (os.environ.get('DRY_RUN').lower() == 'true')
@@ -69,24 +72,31 @@ def main():
logging.error('This script needs to be run in the Github action context.')
return returncode
- if event == 'push' and not cifuzz.build_fuzzers(
- oss_fuzz_project_name, github_repo_name, workspace,
- commit_sha=commit_sha):
+ if event == 'push' and not cifuzz.build_fuzzers(oss_fuzz_project_name,
+ github_repo_name,
+ workspace,
+ commit_sha=commit_sha,
+ sanitizer=sanitizer):
logging.error('Error building fuzzers for project %s with commit %s.',
oss_fuzz_project_name, commit_sha)
return returncode
+
if event == 'pull_request':
with open(os.environ.get('GITHUB_EVENT_PATH'), encoding='utf-8') as file:
event = json.load(file)
pr_ref = 'refs/pull/{0}/merge'.format(event['pull_request']['number'])
- if not cifuzz.build_fuzzers(
- oss_fuzz_project_name, github_repo_name, workspace, pr_ref=pr_ref):
+ if not cifuzz.build_fuzzers(oss_fuzz_project_name,
+ github_repo_name,
+ workspace,
+ pr_ref=pr_ref,
+ sanitizer=sanitizer):
logging.error(
'Error building fuzzers for project %s with pull request %s.',
oss_fuzz_project_name, pr_ref)
return returncode
+
out_dir = os.path.join(workspace, 'out')
- if cifuzz.check_fuzzer_build(out_dir):
+ if cifuzz.check_fuzzer_build(out_dir, sanitizer=sanitizer):
return 0
return returncode
diff --git a/infra/cifuzz/actions/run_fuzzers/action.yml b/infra/cifuzz/actions/run_fuzzers/action.yml
index ca40c4fec..3ce951d83 100644
--- a/infra/cifuzz/actions/run_fuzzers/action.yml
+++ b/infra/cifuzz/actions/run_fuzzers/action.yml
@@ -12,6 +12,9 @@ inputs:
dry-run:
description: 'If set, run the action without actually reporting a failure.'
default: false
+ sanitizer:
+ description: 'The sanitizer to run the fuzzers with.'
+ default: 'address'
runs:
using: 'docker'
image: 'Dockerfile'
@@ -19,3 +22,4 @@ runs:
OSS_FUZZ_PROJECT_NAME: ${{ inputs.oss-fuzz-project-name }}
FUZZ_SECONDS: ${{ inputs.fuzz-seconds }}
DRY_RUN: ${{ inputs.dry-run}}
+ SANITIZER: ${{ inputs.sanitizer }}
diff --git a/infra/cifuzz/actions/run_fuzzers/run_fuzzers_entrypoint.py b/infra/cifuzz/actions/run_fuzzers/run_fuzzers_entrypoint.py
index 4d80e5e7d..7f39388f6 100644
--- a/infra/cifuzz/actions/run_fuzzers/run_fuzzers_entrypoint.py
+++ b/infra/cifuzz/actions/run_fuzzers/run_fuzzers_entrypoint.py
@@ -47,6 +47,7 @@ def main():
GITHUB_WORKSPACE: The shared volume directory where input artifacts are.
DRY_RUN: If true, no failures will surface.
OSS_FUZZ_PROJECT_NAME: The name of the relevant OSS-Fuzz project.
+ SANITIZER: The sanitizer to use when running fuzzers.
Returns:
0 on success or 1 on Failure.
@@ -54,6 +55,8 @@ def main():
fuzz_seconds = int(os.environ.get('FUZZ_SECONDS', 600))
workspace = os.environ.get('GITHUB_WORKSPACE')
oss_fuzz_project_name = os.environ.get('OSS_FUZZ_PROJECT_NAME')
+ sanitizer = os.environ.get('SANITIZER').lower()
+
# Check if failures should not be reported.
dry_run = (os.environ.get('DRY_RUN').lower() == 'true')
@@ -74,8 +77,10 @@ def main():
logging.error('This script needs to be run in the Github action context.')
return returncode
# Run the specified project's fuzzers from the build.
- run_status, bug_found = cifuzz.run_fuzzers(fuzz_seconds, workspace,
- oss_fuzz_project_name)
+ run_status, bug_found = cifuzz.run_fuzzers(fuzz_seconds,
+ workspace,
+ oss_fuzz_project_name,
+ sanitizer=sanitizer)
if not run_status:
logging.error('Error occured while running in workspace %s.', workspace)
return returncode
diff --git a/infra/cifuzz/cifuzz.py b/infra/cifuzz/cifuzz.py
index 2733dd187..4042a9ee6 100644
--- a/infra/cifuzz/cifuzz.py
+++ b/infra/cifuzz/cifuzz.py
@@ -68,7 +68,6 @@ STACKTRACE_END_MARKERS = [
# Default fuzz configuration.
DEFAULT_ENGINE = 'libfuzzer'
-DEFAULT_SANITIZER = 'address'
DEFAULT_ARCHITECTURE = 'x86_64'
# The path to get project's latest report json files.
@@ -80,11 +79,14 @@ logging.basicConfig(
level=logging.DEBUG)
+# pylint: disable=too-many-arguments
+# pylint: disable=too-many-locals
def build_fuzzers(project_name,
project_repo_name,
workspace,
pr_ref=None,
- commit_sha=None):
+ commit_sha=None,
+ sanitizer='address'):
"""Builds all of the fuzzers for a specific OSS-Fuzz project.
Args:
@@ -94,6 +96,7 @@ def build_fuzzers(project_name,
artifacts.
pr_ref: The pull request reference to be built.
commit_sha: The commit sha for the project to be built at.
+ sanitizer: The sanitizer the fuzzers should be built with.
Returns:
True if build succeeded or False on failure.
@@ -104,6 +107,13 @@ def build_fuzzers(project_name,
logging.error('Invalid workspace: %s.', workspace)
return False
+ # Check that sanitizer is valid.
+ if not is_project_sanitizer(sanitizer, project_name):
+ logging.info("%s is not a project sanitizer, defaulting to address.",
+ sanitizer)
+ sanitizer = 'address'
+ logging.info("Using %s as sanitizer.", sanitizer)
+
git_workspace = os.path.join(workspace, 'storage')
os.makedirs(git_workspace, exist_ok=True)
out_dir = os.path.join(workspace, 'out')
@@ -127,12 +137,9 @@ def build_fuzzers(project_name,
build_repo_manager.checkout_pr(pr_ref)
else:
build_repo_manager.checkout_commit(commit_sha)
- except RuntimeError:
- logging.error('Can not check out requested state.')
- return False
- except ValueError:
- logging.error('Invalid commit SHA requested %s.', commit_sha)
- return False
+ except (RuntimeError, ValueError):
+ logging.error('Can not check out requested state %s.', pr_ref or commit_sha)
+ logging.error('Using current repo state.')
# Build Fuzzers using docker run.
command = [
@@ -141,7 +148,7 @@ def build_fuzzers(project_name,
'-e',
'FUZZING_ENGINE=' + DEFAULT_ENGINE,
'-e',
- 'SANITIZER=' + DEFAULT_SANITIZER,
+ 'SANITIZER=' + sanitizer,
'-e',
'ARCHITECTURE=' + DEFAULT_ARCHITECTURE,
'-e',
@@ -177,7 +184,7 @@ def build_fuzzers(project_name,
return True
-def run_fuzzers(fuzz_seconds, workspace, project_name):
+def run_fuzzers(fuzz_seconds, workspace, project_name, sanitizer='address'):
"""Runs all fuzzers for a specific OSS-Fuzz project.
Args:
@@ -185,6 +192,7 @@ def run_fuzzers(fuzz_seconds, workspace, project_name):
workspace: The location in a shared volume to store a git repo and build
artifacts.
project_name: The name of the relevant OSS-Fuzz project.
+ sanitizer: The sanitizer the fuzzers should be run with.
Returns:
(True if run was successful, True if bug was found).
@@ -193,6 +201,14 @@ def run_fuzzers(fuzz_seconds, workspace, project_name):
if not os.path.exists(workspace):
logging.error('Invalid workspace: %s.', workspace)
return False, False
+
+ # Check that sanitizer is valid.
+ if not is_project_sanitizer(sanitizer, project_name):
+ logging.info("%s is not a project sanitizer.", sanitizer)
+ raise ValueError("{0} is not a valid sanitizer for project {1}".format(
+ sanitizer, project_name))
+ logging.info("Using %s as sanitizer.", sanitizer)
+
out_dir = os.path.join(workspace, 'out')
artifacts_dir = os.path.join(out_dir, 'artifacts')
os.makedirs(artifacts_dir, exist_ok=True)
@@ -216,8 +232,11 @@ def run_fuzzers(fuzz_seconds, workspace, project_name):
run_seconds = max(fuzz_seconds // fuzzers_left_to_run,
min_seconds_per_fuzzer)
- target = fuzz_target.FuzzTarget(fuzzer_path, run_seconds, out_dir,
- project_name)
+ target = fuzz_target.FuzzTarget(fuzzer_path,
+ run_seconds,
+ out_dir,
+ project_name,
+ sanitizer=sanitizer)
start_time = time.time()
test_case, stack_trace = target.fuzz()
fuzz_seconds -= (time.time() - start_time)
@@ -234,11 +253,12 @@ def run_fuzzers(fuzz_seconds, workspace, project_name):
return True, False
-def check_fuzzer_build(out_dir):
+def check_fuzzer_build(out_dir, sanitizer='address'):
"""Checks the integrity of the built fuzzers.
Args:
out_dir: The directory containing the fuzzer binaries.
+ sanitizer: The sanitizer the fuzzers are built with.
Returns:
True if fuzzers are correct.
@@ -256,7 +276,7 @@ def check_fuzzer_build(out_dir):
'-e',
'FUZZING_ENGINE=' + DEFAULT_ENGINE,
'-e',
- 'SANITIZER=' + DEFAULT_SANITIZER,
+ 'SANITIZER=' + sanitizer,
'-e',
'ARCHITECTURE=' + DEFAULT_ARCHITECTURE,
]
@@ -483,3 +503,27 @@ def parse_fuzzer_output(fuzzer_output, out_dir):
summary_file_path = os.path.join(out_dir, 'bug_summary.txt')
with open(summary_file_path, 'a') as summary_handle:
summary_handle.write(summary_str)
+
+
+def is_project_sanitizer(sanitizer, oss_fuzz_project_name):
+ """Finds all of the sanitizers a project can use for building and running.
+
+ Args:
+ sanitizer: The desired sanitizer.
+ oss_fuzz_project_name: The name of the relevant OSS-Fuzz project.
+
+ Returns:
+ True if project can use sanitizer.
+ """
+ project_yaml = os.path.join(helper.OSS_FUZZ_DIR, 'projects',
+ oss_fuzz_project_name, 'project.yaml')
+ if not os.path.isfile(project_yaml):
+ logging.error('project.yaml for project %s could not be found.',
+ oss_fuzz_project_name)
+ return False
+
+ # Simple parse to prevent adding pyYAML dependency.
+ with open(project_yaml, 'r') as file_handle:
+ if sanitizer + '\n' in file_handle.read():
+ return True
+ return False
diff --git a/infra/cifuzz/cifuzz_test.py b/infra/cifuzz/cifuzz_test.py
index d76756ffa..4af2837bf 100644
--- a/infra/cifuzz/cifuzz_test.py
+++ b/infra/cifuzz/cifuzz_test.py
@@ -50,6 +50,12 @@ EXAMPLE_NOCRASH_FUZZER = 'example_nocrash_fuzzer'
# A fuzzer to be built in build_fuzzers integration tests.
EXAMPLE_BUILD_FUZZER = 'do_stuff_fuzzer'
+MEMORY_FUZZER_DIR = os.path.join(TEST_FILES_PATH, 'out', 'memory')
+MEMORY_FUZZER = 'curl_fuzzer_memory'
+
+UNDEFINED_FUZZER_DIR = os.path.join(TEST_FILES_PATH, 'out', 'undefined')
+UNDEFINED_FUZZER = 'curl_fuzzer_undefined'
+
# pylint: disable=no-self-use
@@ -88,7 +94,7 @@ class BuildFuzzersIntegrationTest(unittest.TestCase):
with tempfile.TemporaryDirectory() as tmp_dir:
out_path = os.path.join(tmp_dir, 'out')
os.mkdir(out_path)
- self.assertFalse(
+ self.assertTrue(
cifuzz.build_fuzzers(EXAMPLE_PROJECT,
'oss-fuzz',
tmp_dir,
@@ -134,16 +140,70 @@ class BuildFuzzersIntegrationTest(unittest.TestCase):
))
-class RunFuzzersIntegrationTest(unittest.TestCase):
+class RunMemoryFuzzerIntegrationTest(unittest.TestCase):
"""Test build_fuzzers function in the cifuzz module."""
def tearDown(self):
"""Remove any existing crashes and test files."""
- out_dir = os.path.join(TEST_FILES_PATH, 'out')
+ out_dir = os.path.join(MEMORY_FUZZER_DIR, 'out')
+ for out_file in os.listdir(out_dir):
+ out_path = os.path.join(out_dir, out_file)
+ #pylint: disable=consider-using-in
+ if out_file == MEMORY_FUZZER:
+ continue
+ if os.path.isdir(out_path):
+ shutil.rmtree(out_path)
+ else:
+ os.remove(out_path)
+
+ def test_run_with_memory_sanitizer(self):
+ """Test run_fuzzers with a valid build."""
+ run_success, bug_found = cifuzz.run_fuzzers(10,
+ MEMORY_FUZZER_DIR,
+ 'curl',
+ sanitizer='memory')
+ self.assertTrue(run_success)
+ self.assertFalse(bug_found)
+
+
+class RunUndefinedFuzzerIntegrationTest(unittest.TestCase):
+ """Test build_fuzzers function in the cifuzz module."""
+
+ def tearDown(self):
+ """Remove any existing crashes and test files."""
+ out_dir = os.path.join(UNDEFINED_FUZZER_DIR, 'out')
for out_file in os.listdir(out_dir):
out_path = os.path.join(out_dir, out_file)
#pylint: disable=consider-using-in
- if out_file == EXAMPLE_CRASH_FUZZER or out_file == EXAMPLE_NOCRASH_FUZZER:
+ if out_file == UNDEFINED_FUZZER:
+ continue
+ if os.path.isdir(out_path):
+ shutil.rmtree(out_path)
+ else:
+ os.remove(out_path)
+
+ def test_run_with_undefined_sanitizer(self):
+ """Test run_fuzzers with a valid build."""
+ run_success, bug_found = cifuzz.run_fuzzers(10,
+ UNDEFINED_FUZZER_DIR,
+ 'curl',
+ sanitizer='undefined')
+ self.assertTrue(run_success)
+ self.assertFalse(bug_found)
+
+
+class RunAddressFuzzersIntegrationTest(unittest.TestCase):
+ """Test build_fuzzers function in the cifuzz module."""
+
+ def tearDown(self):
+ """Remove any existing crashes and test files."""
+ out_dir = os.path.join(TEST_FILES_PATH, 'out')
+ files_to_keep = [
+ 'undefined', 'memory', EXAMPLE_CRASH_FUZZER, EXAMPLE_NOCRASH_FUZZER
+ ]
+ for out_file in os.listdir(out_dir):
+ out_path = os.path.join(out_dir, out_file)
+ if out_file in files_to_keep:
continue
if os.path.isdir(out_path):
shutil.rmtree(out_path)
@@ -157,7 +217,10 @@ class RunFuzzersIntegrationTest(unittest.TestCase):
# OSS-Fuzz build.
with mock.patch.object(fuzz_target.FuzzTarget,
'is_reproducible',
- side_effect=[True, False]):
+ side_effect=[True, False]), mock.patch.object(
+ cifuzz,
+ 'is_project_sanitizer',
+ return_value=True):
run_success, bug_found = cifuzz.run_fuzzers(10, TEST_FILES_PATH,
EXAMPLE_PROJECT)
build_dir = os.path.join(TEST_FILES_PATH, 'out', 'oss_fuzz_latest')
@@ -170,7 +233,10 @@ class RunFuzzersIntegrationTest(unittest.TestCase):
"""Test run_fuzzers with a bug found in OSS-Fuzz before."""
with mock.patch.object(fuzz_target.FuzzTarget,
'is_reproducible',
- side_effect=[True, True]):
+ side_effect=[True, True]), mock.patch.object(
+ cifuzz,
+ 'is_project_sanitizer',
+ return_value=True):
run_success, bug_found = cifuzz.run_fuzzers(10, TEST_FILES_PATH,
EXAMPLE_PROJECT)
build_dir = os.path.join(TEST_FILES_PATH, 'out', 'oss_fuzz_latest')
@@ -181,7 +247,8 @@ class RunFuzzersIntegrationTest(unittest.TestCase):
def test_invalid_build(self):
"""Test run_fuzzers with an invalid build."""
- with tempfile.TemporaryDirectory() as tmp_dir:
+ with tempfile.TemporaryDirectory() as tmp_dir, unittest.mock.patch.object(
+ cifuzz, 'is_project_sanitizer', return_value=True):
out_path = os.path.join(tmp_dir, 'out')
os.mkdir(out_path)
run_success, bug_found = cifuzz.run_fuzzers(10, tmp_dir, EXAMPLE_PROJECT)
@@ -190,7 +257,8 @@ class RunFuzzersIntegrationTest(unittest.TestCase):
def test_invalid_fuzz_seconds(self):
"""Tests run_fuzzers with an invalid fuzz seconds."""
- with tempfile.TemporaryDirectory() as tmp_dir:
+ with tempfile.TemporaryDirectory() as tmp_dir, unittest.mock.patch.object(
+ cifuzz, 'is_project_sanitizer', return_value=True):
out_path = os.path.join(tmp_dir, 'out')
os.mkdir(out_path)
run_success, bug_found = cifuzz.run_fuzzers(0, tmp_dir, EXAMPLE_PROJECT)
@@ -433,5 +501,57 @@ class KeepAffectedFuzzersUnitTest(unittest.TestCase):
self.assertEqual(2, len(os.listdir(tmp_dir)))
+class IsProjectSanitizerUnitTest(unittest.TestCase):
+ """Class to test the is_project_sanitizer function in the cifuzz module.
+ Note: This test relies on the curl project being an OSS-Fuzz project.
+ """
+
+ def test_valid_project_curl(self):
+ """Test if sanitizers can be detected from project.yaml"""
+ self.assertTrue(cifuzz.is_project_sanitizer('memory', 'curl'))
+ self.assertTrue(cifuzz.is_project_sanitizer('address', 'curl'))
+ self.assertTrue(cifuzz.is_project_sanitizer('undefined', 'curl'))
+ self.assertFalse(cifuzz.is_project_sanitizer('not-a-san', 'curl'))
+
+ def test_valid_project_example(self):
+ """Test if sanitizers can be detected from project.yaml"""
+ self.assertFalse(cifuzz.is_project_sanitizer('memory', 'example'))
+ self.assertFalse(cifuzz.is_project_sanitizer('address', 'example'))
+ self.assertFalse(cifuzz.is_project_sanitizer('undefined', 'example'))
+ self.assertFalse(cifuzz.is_project_sanitizer('not-a-san', 'example'))
+
+ def test_invalid_project(self):
+ """Tests that invalid projects return false."""
+ self.assertFalse(cifuzz.is_project_sanitizer('memory', 'notaproj'))
+ self.assertFalse(cifuzz.is_project_sanitizer('address', 'notaproj'))
+ self.assertFalse(cifuzz.is_project_sanitizer('undefined', 'notaproj'))
+
+
+@unittest.skip('Test is too long to be run with presubmit.')
+class BuildSantizerIntegrationTest(unittest.TestCase):
+ """Class to test the is_project_sanitizer function in the cifuzz module.
+ Note: This test relies on the curl project being an OSS-Fuzz project."""
+
+ def test_valid_project_curl_memory(self):
+ """Test if sanitizers can be detected from project.yaml"""
+ with tempfile.TemporaryDirectory() as tmp_dir:
+ self.assertTrue(
+ cifuzz.build_fuzzers('curl',
+ 'curl',
+ tmp_dir,
+ pr_ref='fake_pr',
+ sanitizer='memory'))
+
+ def test_valid_project_curl_undefined(self):
+ """Test if sanitizers can be detected from project.yaml"""
+ with tempfile.TemporaryDirectory() as tmp_dir:
+ self.assertTrue(
+ cifuzz.build_fuzzers('curl',
+ 'curl',
+ tmp_dir,
+ pr_ref='fake_pr',
+ sanitizer='undefined'))
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/infra/cifuzz/fuzz_target.py b/infra/cifuzz/fuzz_target.py
index d32322a93..7050ae2d7 100644
--- a/infra/cifuzz/fuzz_target.py
+++ b/infra/cifuzz/fuzz_target.py
@@ -51,9 +51,6 @@ BUILD_ARCHIVE_NAME = 'oss_fuzz_latest.zip'
# Zip file name containing the corpus.
CORPUS_ZIP_NAME = 'public.zip'
-# The sanitizer build to download.
-SANITIZER = 'address'
-
# The number of reproduce attempts for a crash.
REPRODUCE_ATTEMPTS = 10
@@ -83,7 +80,13 @@ class FuzzTarget:
project_name: The name of the relevant OSS-Fuzz project.
"""
- def __init__(self, target_path, duration, out_dir, project_name=None):
+ #pylint: disable=too-many-arguments
+ def __init__(self,
+ target_path,
+ duration,
+ out_dir,
+ project_name=None,
+ sanitizer='address'):
"""Represents a single fuzz target.
Note: project_name should be none when the fuzzer being run is not
@@ -100,6 +103,7 @@ class FuzzTarget:
self.target_path = target_path
self.out_dir = out_dir
self.project_name = project_name
+ self.sanitizer = sanitizer
def fuzz(self):
"""Starts the fuzz target run for the length of time specified by duration.
@@ -119,8 +123,8 @@ class FuzzTarget:
command += ['-v', '%s:%s' % (self.out_dir, '/out')]
command += [
- '-e', 'FUZZING_ENGINE=libfuzzer', '-e', 'SANITIZER=address', '-e',
- 'RUN_FUZZER_MODE=interactive', 'gcr.io/oss-fuzz-base/base-runner',
+ '-e', 'FUZZING_ENGINE=libfuzzer', '-e', 'SANITIZER=' + self.sanitizer,
+ '-e', 'RUN_FUZZER_MODE=interactive', 'gcr.io/oss-fuzz-base/base-runner',
'bash', '-c'
]
@@ -301,7 +305,7 @@ class FuzzTarget:
return None
version = VERSION_STRING.format(project_name=self.project_name,
- sanitizer=SANITIZER)
+ sanitizer=self.sanitizer)
version_url = url_join(GCS_BASE_URL, CLUSTERFUZZ_BUILDS, self.project_name,
version)
try:
diff --git a/infra/cifuzz/test_files/out/memory/out/curl_fuzzer_memory b/infra/cifuzz/test_files/out/memory/out/curl_fuzzer_memory
new file mode 100755
index 000000000..c602ce970
--- /dev/null
+++ b/infra/cifuzz/test_files/out/memory/out/curl_fuzzer_memory
Binary files differ
diff --git a/infra/cifuzz/test_files/out/undefined/out/curl_fuzzer_undefined b/infra/cifuzz/test_files/out/undefined/out/curl_fuzzer_undefined
new file mode 100755
index 000000000..504cab108
--- /dev/null
+++ b/infra/cifuzz/test_files/out/undefined/out/curl_fuzzer_undefined
Binary files differ