cifuzz: Fix artifacts uploading issues. (#6646)

This commit is contained in:
Oliver Chang 2021-10-27 12:24:26 +11:00 committed by GitHub
parent 259abeacb4
commit f460c03c8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 67 additions and 61 deletions

View File

@ -17,12 +17,14 @@ import logging
import os
import shutil
import stat
import tempfile
import clusterfuzz.environment
import clusterfuzz.fuzz
import config_utils
import logs
import stack_parser
logs.init()
@ -106,6 +108,24 @@ class FuzzTarget: # pylint: disable=too-many-instance-attributes
self.latest_corpus_path)
return self.latest_corpus_path
def _target_artifact_path(self):
"""Target artifact path."""
artifact_path = os.path.join(self.workspace.artifacts, self.target_name,
self.config.sanitizer)
os.makedirs(artifact_path, exist_ok=True)
return artifact_path
def _save_crash(self, crash):
"""Add stacktraces to crashes."""
target_reproducer_path = os.path.join(self._target_artifact_path(),
os.path.basename(crash.input_path))
shutil.copy(crash.input_path, target_reproducer_path)
bug_summary_artifact_path = target_reproducer_path + '.summary'
stack_parser.parse_fuzzer_output(crash.stacktrace,
bug_summary_artifact_path)
return target_reproducer_path
def prune(self):
"""Prunes the corpus and returns the result."""
self._download_corpus()
@ -117,7 +137,7 @@ class FuzzTarget: # pylint: disable=too-many-instance-attributes
result = engine_impl.minimize_corpus(self.target_path, [],
[self.latest_corpus_path],
self.pruned_corpus_path,
self.workspace.artifacts,
self._target_artifact_path(),
self.duration)
return FuzzResult(None, result.logs, self.pruned_corpus_path)
@ -134,32 +154,36 @@ class FuzzTarget: # pylint: disable=too-many-instance-attributes
corpus_path = self.latest_corpus_path
logging.info('Starting fuzzing')
with clusterfuzz.environment.Environment(config_utils.DEFAULT_ENGINE,
self.config.sanitizer,
self.target_path,
interactive=True) as env:
engine_impl = clusterfuzz.fuzz.get_engine(config_utils.DEFAULT_ENGINE)
options = engine_impl.prepare(corpus_path, env.target_path, env.build_dir)
options.merge_back_new_testcases = False
options.analyze_dictionary = False
options.arguments.extend(LIBFUZZER_OPTIONS)
with tempfile.TemporaryDirectory() as artifacts_dir:
with clusterfuzz.environment.Environment(config_utils.DEFAULT_ENGINE,
self.config.sanitizer,
self.target_path,
interactive=True) as env:
engine_impl = clusterfuzz.fuzz.get_engine(config_utils.DEFAULT_ENGINE)
options = engine_impl.prepare(corpus_path, env.target_path,
env.build_dir)
options.merge_back_new_testcases = False
options.analyze_dictionary = False
options.arguments.extend(LIBFUZZER_OPTIONS)
result = engine_impl.fuzz(self.target_path, options,
self.workspace.artifacts, self.duration)
result = engine_impl.fuzz(self.target_path, options, artifacts_dir,
self.duration)
# Libfuzzer timeout was reached.
if not result.crashes:
logging.info('Fuzzer %s finished with no crashes discovered.',
self.target_name)
return FuzzResult(None, None, self.latest_corpus_path)
# Libfuzzer timeout was reached.
if not result.crashes:
logging.info('Fuzzer %s finished with no crashes discovered.',
self.target_name)
return FuzzResult(None, None, self.latest_corpus_path)
# Only report first crash.
crash = result.crashes[0]
logging.info('Fuzzer: %s. Detected bug.', self.target_name)
# Only report first crash.
crash = result.crashes[0]
logging.info('Fuzzer: %s. Detected bug:\n%s', self.target_name,
crash.stacktrace)
if self.is_crash_reportable(crash.input_path):
# We found a bug in the fuzz target and we will report it.
return FuzzResult(crash.input_path, result.logs, self.latest_corpus_path)
if self.is_crash_reportable(crash.input_path):
# We found a bug in the fuzz target and we will report it.
saved_path = self._save_crash(crash)
return FuzzResult(saved_path, result.logs, self.latest_corpus_path)
# We found a bug but we won't report it.
return FuzzResult(None, None, self.latest_corpus_path)

View File

@ -220,5 +220,25 @@ class IsCrashReportableTest(fake_filesystem_unittest.TestCase):
'introduced.')
class FuzzTest(fake_filesystem_unittest.TestCase):
"""Fuzz test."""
def setUp(self):
"""Sets up example fuzz target to test is_reproducible method."""
self.setUpPyfakefs()
deployment = _create_deployment()
config = deployment.config
workspace = deployment.workspace
self.fuzz_target = fuzz_target.FuzzTarget('/path/fuzz-target', 10,
workspace, deployment, config)
def test_get_fuzz_target_artifact(self):
"""Tests that get_fuzz_target_artifact works as intended."""
# pylint: disable=protected-access
fuzz_target_artifact = self.fuzz_target._target_artifact_path()
self.assertEqual('/workspace/out/artifacts/fuzz-target/address',
fuzz_target_artifact)
if __name__ == '__main__':
unittest.main()

View File

@ -15,14 +15,12 @@
import enum
import logging
import os
import shutil
import sys
import time
import clusterfuzz_deployment
import fuzz_target
import generate_coverage_report
import stack_parser
import workspace_utils
# pylint: disable=wrong-import-position,import-error
@ -106,13 +104,6 @@ class BaseFuzzTargetRunner:
bug is found."""
raise NotImplementedError('Child class must implement method.')
def get_fuzz_target_artifact(self, target, artifact_name):
"""Returns the path of a fuzzing artifact named |artifact_name| for
|fuzz_target|."""
artifact_name = (f'{target.target_name}-{self.config.sanitizer}-'
f'{artifact_name}')
return os.path.join(self.workspace.artifacts, artifact_name)
def create_fuzz_target_obj(self, target_path, run_seconds):
"""Returns a fuzz target object."""
return fuzz_target.FuzzTarget(target_path, run_seconds, self.workspace,
@ -149,15 +140,6 @@ class BaseFuzzTargetRunner:
target.target_name)
continue
# TODO(metzman): Do this with filestore.
testcase_artifact_path = self.get_fuzz_target_artifact(
target, os.path.basename(result.testcase))
shutil.move(result.testcase, testcase_artifact_path)
bug_summary_artifact_path = self.get_fuzz_target_artifact(
target, 'bug-summary.txt')
stack_parser.parse_fuzzer_output(result.stacktrace,
bug_summary_artifact_path)
bug_found = True
if self.quit_on_bug_found:
logging.info('Bug found. Stopping fuzzing.')

View File

@ -211,24 +211,6 @@ class BaseFuzzTargetRunnerTest(unittest.TestCase):
out_path)
self._test_initialize_fail(expected_error_args, workspace=tmp_dir)
def test_get_fuzz_target_artifact(self):
"""Tests that get_fuzz_target_artifact works as intended."""
with tempfile.TemporaryDirectory() as tmp_dir:
runner = self._create_runner(workspace=tmp_dir)
crashes_dir = 'crashes-dir'
runner.crashes_dir = crashes_dir
artifact_name = 'artifact-name'
target = mock.MagicMock()
target_name = 'target_name'
target.target_name = target_name
fuzz_target_artifact = runner.get_fuzz_target_artifact(
target, artifact_name)
expected_fuzz_target_artifact = os.path.join(
tmp_dir, 'out', 'artifacts', 'target_name-address-artifact-name')
self.assertEqual(fuzz_target_artifact, expected_fuzz_target_artifact)
class CiFuzzTargetRunnerTest(fake_filesystem_unittest.TestCase):
"""Tests that CiFuzzTargetRunner works as intended."""
@ -264,8 +246,6 @@ class CiFuzzTargetRunnerTest(fake_filesystem_unittest.TestCase):
magic_mock.target_name = 'target1'
mock_create_fuzz_target_obj.return_value = magic_mock
self.assertTrue(runner.run_fuzz_targets())
self.assertIn('target1-address-testcase',
os.listdir(runner.workspace.artifacts))
self.assertEqual(mock_run_fuzz_target.call_count, 1)