Centipede's CI build, trial build, and build tests (#8422)

Adding CI build, trial build, and build tests.

Co-authored-by: Oliver Chang <oliverchang@users.noreply.github.com>
This commit is contained in:
Dongge Liu 2022-09-16 09:25:49 +10:00 committed by GitHub
parent 0a98805261
commit 2fa71e3c7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 407 additions and 17 deletions

View File

@ -114,7 +114,16 @@ function check_engine {
cat $FUZZER_OUTPUT
return 1
fi
return 0
elif [[ "$FUZZING_ENGINE" == centipede && "$SANITIZER" == "none" ]]; then
# Only perform run test on unsanitized binary for now.
# TODO(Dongge): Support run test for sanitized binaries as well.
timeout --preserve-status -s INT 20s run_fuzzer $FUZZER_NAME &>$FUZZER_OUTPUT
CHECK_PASSED=$(egrep "\[0] begin-fuzz: ft: 0 cov: 0" -c $FUZZER_OUTPUT)
if (( $CHECK_PASSED == 0 )); then
echo "BAD BUILD: fuzzing $FUZZER with centipede failed."
cat $FUZZER_OUTPUT
return 1
fi
fi
# TODO: add checks for other fuzzing engines if possible.

View File

@ -72,6 +72,16 @@ function get_dictionary() {
fi
}
function get_extra_binaries() {
[[ "$FUZZING_ENGINE" != "centipede" ]] && return
extra_binaries="$OUT/**_${SANITIZER}/${FUZZER}"
if compgen -G "$extra_binaries" >> /dev/null; then
printf -- "--extra_binaries %s" \""$extra_binaries\""
fi
}
rm -rf $FUZZER_OUT && mkdir -p $FUZZER_OUT
SEED_CORPUS="${FUZZER}_seed_corpus.zip"
@ -177,7 +187,7 @@ elif [[ "$FUZZING_ENGINE" = centipede ]]; then
# --address_space_limit_mb=0: No address space limit.
# --binary: The target binary under test without sanitizer.
# --extra_binary: The target binaries under test with sanitizers.
CMD_LINE="$OUT/centipede --workdir=\"$OUT/workdir\" --corpus_dir=\"$CORPUS_DIR\" --fork_server=1 --exit_on_crash=1 --timeout=1200 --rss_limit_mb=4096 --address_space_limit_mb=0 $(get_dictionary) --binary=\"$OUT/${FUZZER}\" --extra_binaries=\"$OUT/**_${SANITIZER}/${FUZZER}\" $*"
CMD_LINE="$OUT/centipede --workdir=\"$OUT/workdir\" --corpus_dir=\"$CORPUS_DIR\" --fork_server=1 --exit_on_crash=1 --timeout=1200 --rss_limit_mb=4096 --address_space_limit_mb=0 $(get_dictionary) --binary=\"$OUT/${FUZZER}\" $(get_extra_binaries) $*"
else
CMD_LINE="$OUT/$FUZZER $FUZZER_ARGS $*"

View File

@ -75,7 +75,7 @@ ENGINE_INFO = {
supported_architectures=['x86_64']),
'centipede':
EngineInfo(upload_bucket='clusterfuzz-builds-centipede',
supported_sanitizers=['address'],
supported_sanitizers=['address', 'none'],
supported_architectures=['x86_64']),
}

View File

@ -115,6 +115,14 @@ def get_sanitizer_strings(sanitizers):
return processed_sanitizers
def set_default_sanitizer_for_centipede(project_yaml):
"""Adds none as a sanitizer for centipede in yaml if it does not exist yet."""
# Centipede requires a separate unsanitized binary to use sanitized ones.
if ('centipede' in project_yaml['fuzzing_engines'] and
project_yaml['sanitizers'] and 'none' not in project_yaml['sanitizers']):
project_yaml['sanitizers'].append('none')
class Project: # pylint: disable=too-many-instance-attributes
"""Class representing an OSS-Fuzz project."""
@ -164,6 +172,9 @@ def set_yaml_defaults(project_yaml):
project_yaml.setdefault('run_tests', True)
project_yaml.setdefault('coverage_extra_args', '')
project_yaml.setdefault('labels', {})
# Adds 'none' as a sanitizer for centipede to the project yaml by default,
# because Centipede always requires a separate build of unsanitized binary.
set_default_sanitizer_for_centipede(project_yaml)
def is_supported_configuration(build):

View File

@ -75,6 +75,42 @@ class TestRequestCoverageBuilds(fake_filesystem_unittest.TestCase):
config)
self.assertEqual(build_steps, expected_build_steps)
@mock.patch('build_lib.get_signed_url', return_value='test_url')
@mock.patch('build_project.get_datetime_now',
return_value=test_utils.FAKE_DATETIME)
def test_get_centipede_build_steps(self, mock_url, mock_get_datetime_now):
"""Test for get_build_steps of centipede."""
del mock_url, mock_get_datetime_now
# The none sanitizer should be added automatically when other sanitizers are
# specified by the users.
project_yaml_contents = (
'language: c++\n'
'fuzzing_engines:\n'
' - centipede\n'
'sanitizers:\n'
' - address\n'
'architectures:\n'
' - x86_64\n'
'main_repo: https://github.com/google/centipede.git\n')
self.fs.create_dir(test_utils.PROJECT_DIR)
test_utils.create_project_data(test_utils.PROJECT, project_yaml_contents)
expected_build_steps_file_path = test_utils.get_test_data_file_path(
'expected_centipede_build_steps.json')
self.fs.add_real_file(expected_build_steps_file_path)
with open(expected_build_steps_file_path) as expected_build_steps_file:
expected_build_steps = json.load(expected_build_steps_file)
config = build_project.Config(False, False, None, False, True)
project_yaml, dockerfile = build_project.get_project_data(
test_utils.PROJECT)
build_steps = build_project.get_build_steps(test_utils.PROJECT,
project_yaml, dockerfile,
test_utils.IMAGE_PROJECT,
test_utils.BASE_IMAGES_PROJECT,
config)
self.assertEqual(build_steps, expected_build_steps)
if __name__ == '__main__':
unittest.main(exit=False)

View File

@ -0,0 +1,308 @@
[
{
"args": [
"clone",
"https://github.com/google/oss-fuzz.git",
"--depth",
"1"
],
"name": "gcr.io/cloud-builders/git"
},
{
"name": "gcr.io/cloud-builders/docker",
"args": [
"build",
"--tag",
"gcr.io/oss-fuzz/test-project",
"."
],
"dir": "oss-fuzz/projects/test-project"
},
{
"name": "gcr.io/oss-fuzz/test-project",
"args": [
"bash",
"-c",
"srcmap > /workspace/srcmap.json && cat /workspace/srcmap.json"
],
"env": [
"OSSFUZZ_REVISION=$REVISION_ID",
"FUZZING_LANGUAGE=c++"
],
"id": "srcmap"
},
{
"name": "gcr.io/cloud-builders/docker",
"env": [
"ARCHITECTURE=x86_64",
"FUZZING_ENGINE=centipede",
"FUZZING_LANGUAGE=c++",
"HOME=/root",
"OUT=/workspace/out/centipede-address-x86_64",
"SANITIZER=address"
],
"args": [
"run",
"--platform",
"linux/amd64",
"-v",
"/workspace:/workspace",
"-e",
"ARCHITECTURE=x86_64",
"-e",
"FUZZING_ENGINE=centipede",
"-e",
"FUZZING_LANGUAGE=c++",
"-e",
"HOME=/root",
"-e",
"OUT=/workspace/out/centipede-address-x86_64",
"-e",
"SANITIZER=address",
"-t",
"gcr.io/oss-fuzz/test-project",
"bash",
"-c",
"rm -r /out && cd /src && cd /src && mkdir -p /workspace/out/centipede-address-x86_64 && compile || (echo \"********************************************************************************\nFailed to build.\nTo reproduce, run:\npython infra/helper.py build_image test-project\npython infra/helper.py build_fuzzers --sanitizer address --engine centipede --architecture x86_64 test-project\n********************************************************************************\" && false)"
],
"id": "compile-centipede-address-x86_64"
},
{
"name": "gcr.io/cloud-builders/docker",
"env": [
"ARCHITECTURE=x86_64",
"FUZZING_ENGINE=centipede",
"FUZZING_LANGUAGE=c++",
"HOME=/root",
"OUT=/workspace/out/centipede-address-x86_64",
"SANITIZER=address"
],
"args": [
"run",
"--platform",
"linux/amd64",
"-v",
"/workspace:/workspace",
"-e",
"ARCHITECTURE=x86_64",
"-e",
"FUZZING_ENGINE=centipede",
"-e",
"FUZZING_LANGUAGE=c++",
"-e",
"HOME=/root",
"-e",
"OUT=/workspace/out/centipede-address-x86_64",
"-e",
"SANITIZER=address",
"-t",
"gcr.io/oss-fuzz-base/base-runner",
"bash",
"-c",
"test_all.py || (echo \"********************************************************************************\nBuild checks failed.\nTo reproduce, run:\npython infra/helper.py build_image test-project\npython infra/helper.py build_fuzzers --sanitizer address --engine centipede --architecture x86_64 test-project\npython infra/helper.py check_build --sanitizer address --engine centipede --architecture x86_64 test-project\n********************************************************************************\" && false)"
],
"id": "build-check-centipede-address-x86_64"
},
{
"name": "gcr.io/oss-fuzz-base/base-runner",
"env": [
"ARCHITECTURE=x86_64",
"FUZZING_ENGINE=centipede",
"FUZZING_LANGUAGE=c++",
"HOME=/root",
"OUT=/workspace/out/centipede-address-x86_64",
"SANITIZER=address"
],
"args": [
"bash",
"-c",
"targets_list > /workspace/targets.list.address"
]
},
{
"name": "gcr.io/oss-fuzz/test-project",
"args": [
"bash",
"-c",
"cd /workspace/out/centipede-address-x86_64 && zip -r test-project-address-202001010000.zip *"
]
},
{
"name": "gcr.io/oss-fuzz-base/uploader",
"args": [
"/workspace/srcmap.json",
"test_url"
]
},
{
"name": "gcr.io/oss-fuzz-base/uploader",
"args": [
"/workspace/out/centipede-address-x86_64/test-project-address-202001010000.zip",
"test_url"
]
},
{
"name": "gcr.io/oss-fuzz-base/uploader",
"args": [
"/workspace/targets.list.address",
"test_url"
]
},
{
"name": "gcr.io/cloud-builders/curl",
"args": [
"-H",
"Content-Type: text/plain",
"-X",
"PUT",
"-d",
"test-project-address-202001010000.zip",
"test_url"
]
},
{
"name": "gcr.io/oss-fuzz/test-project",
"args": [
"bash",
"-c",
"rm -r /workspace/out/centipede-address-x86_64"
]
},
{
"name": "gcr.io/cloud-builders/docker",
"env": [
"ARCHITECTURE=x86_64",
"FUZZING_ENGINE=centipede",
"FUZZING_LANGUAGE=c++",
"HOME=/root",
"OUT=/workspace/out/centipede-none-x86_64",
"SANITIZER=none"
],
"args": [
"run",
"--platform",
"linux/amd64",
"-v",
"/workspace:/workspace",
"-e",
"ARCHITECTURE=x86_64",
"-e",
"FUZZING_ENGINE=centipede",
"-e",
"FUZZING_LANGUAGE=c++",
"-e",
"HOME=/root",
"-e",
"OUT=/workspace/out/centipede-none-x86_64",
"-e",
"SANITIZER=none",
"-t",
"gcr.io/oss-fuzz/test-project",
"bash",
"-c",
"rm -r /out && cd /src && cd /src && mkdir -p /workspace/out/centipede-none-x86_64 && compile || (echo \"********************************************************************************\nFailed to build.\nTo reproduce, run:\npython infra/helper.py build_image test-project\npython infra/helper.py build_fuzzers --sanitizer none --engine centipede --architecture x86_64 test-project\n********************************************************************************\" && false)"
],
"id": "compile-centipede-none-x86_64"
},
{
"name": "gcr.io/cloud-builders/docker",
"env": [
"ARCHITECTURE=x86_64",
"FUZZING_ENGINE=centipede",
"FUZZING_LANGUAGE=c++",
"HOME=/root",
"OUT=/workspace/out/centipede-none-x86_64",
"SANITIZER=none"
],
"args": [
"run",
"--platform",
"linux/amd64",
"-v",
"/workspace:/workspace",
"-e",
"ARCHITECTURE=x86_64",
"-e",
"FUZZING_ENGINE=centipede",
"-e",
"FUZZING_LANGUAGE=c++",
"-e",
"HOME=/root",
"-e",
"OUT=/workspace/out/centipede-none-x86_64",
"-e",
"SANITIZER=none",
"-t",
"gcr.io/oss-fuzz-base/base-runner",
"bash",
"-c",
"test_all.py || (echo \"********************************************************************************\nBuild checks failed.\nTo reproduce, run:\npython infra/helper.py build_image test-project\npython infra/helper.py build_fuzzers --sanitizer none --engine centipede --architecture x86_64 test-project\npython infra/helper.py check_build --sanitizer none --engine centipede --architecture x86_64 test-project\n********************************************************************************\" && false)"
],
"id": "build-check-centipede-none-x86_64"
},
{
"name": "gcr.io/oss-fuzz-base/base-runner",
"env": [
"ARCHITECTURE=x86_64",
"FUZZING_ENGINE=centipede",
"FUZZING_LANGUAGE=c++",
"HOME=/root",
"OUT=/workspace/out/centipede-none-x86_64",
"SANITIZER=none"
],
"args": [
"bash",
"-c",
"targets_list > /workspace/targets.list.none"
]
},
{
"name": "gcr.io/oss-fuzz/test-project",
"args": [
"bash",
"-c",
"cd /workspace/out/centipede-none-x86_64 && zip -r test-project-none-202001010000.zip *"
]
},
{
"name": "gcr.io/oss-fuzz-base/uploader",
"args": [
"/workspace/srcmap.json",
"test_url"
]
},
{
"name": "gcr.io/oss-fuzz-base/uploader",
"args": [
"/workspace/out/centipede-none-x86_64/test-project-none-202001010000.zip",
"test_url"
]
},
{
"name": "gcr.io/oss-fuzz-base/uploader",
"args": [
"/workspace/targets.list.none",
"test_url"
]
},
{
"name": "gcr.io/cloud-builders/curl",
"args": [
"-H",
"Content-Type: text/plain",
"-X",
"PUT",
"-d",
"test-project-none-202001010000.zip",
"test_url"
]
},
{
"name": "gcr.io/oss-fuzz/test-project",
"args": [
"bash",
"-c",
"rm -r /workspace/out/centipede-none-x86_64"
]
}
]

View File

@ -109,7 +109,7 @@ def get_args(args=None):
help='Sanitizers.')
parser.add_argument('--fuzzing-engines',
required=False,
default=['afl', 'libfuzzer', 'honggfuzz'],
default=['afl', 'libfuzzer', 'honggfuzz', 'centipede'],
nargs='+',
help='Fuzzing engines.')
parser.add_argument('--branch',

View File

@ -68,7 +68,7 @@ class TestShouldBuild(unittest.TestCase):
def test_libfuzzer_coverage_build(self):
"""Tests that should_build returns True for coverage build of a project
specifying 'libfuzzer' and for fuzzing_engines."""
specifying 'libfuzzer' for fuzzing_engines."""
_set_coverage_build()
project_yaml = {
'language': 'c++',
@ -79,7 +79,7 @@ class TestShouldBuild(unittest.TestCase):
def test_go_coverage_build(self):
"""Tests that should_build returns True for coverage build of a project
specifying 'libfuzzer' and for fuzzing_engines."""
specifying 'libfuzzer' for fuzzing_engines."""
_set_coverage_build()
project_yaml = {'language': 'go'}
self.assertTrue(build.should_build(project_yaml))
@ -96,3 +96,29 @@ class TestShouldBuild(unittest.TestCase):
'sanitizers': ['address']
}
self.assertFalse(build.should_build(project_yaml))
def test_centipede_none_build(self):
"""Tests that should_build returns True for none sanitizer build of a
project specifying 'centipede' for fuzzing_engines."""
os.environ['SANITIZER'] = 'none'
os.environ['ENGINE'] = 'centipede'
os.environ['ARCHITECTURE'] = 'x86_64'
project_yaml = {
'language': 'c++',
'fuzzing_engines': ['centipede'],
'sanitizers': ['none']
}
self.assertTrue(build.should_build(project_yaml))
def test_centipede_address_build(self):
"""Tests that should_build returns True for address sanitizer build of a
project specifying 'centipede' for fuzzing_engines."""
os.environ['SANITIZER'] = 'address'
os.environ['ENGINE'] = 'centipede'
os.environ['ARCHITECTURE'] = 'x86_64'
project_yaml = {
'language': 'c++',
'fuzzing_engines': ['centipede'],
'sanitizers': ['address']
}
self.assertTrue(build.should_build(project_yaml))

View File

@ -746,14 +746,6 @@ def _add_oss_fuzz_ci_if_needed(env):
env.append('OSS_FUZZ_CI=' + oss_fuzz_ci)
def get_target_out_dir(args):
"""Change the out/ to a subdir when building wth Centipede and sanitizers"""
if args.engine == 'centipede' and args.sanitizer != 'none':
return os.path.join(args.project.out,
f'{args.project.name}_{args.sanitizer}')
return args.project.out
def check_build(args):
"""Checks that fuzzers in the container execute without errors."""
if not check_project_exists(args.project):
@ -773,10 +765,8 @@ def check_build(args):
if args.e:
env += args.e
target_dir = get_target_out_dir(args)
run_args = _env_to_docker_args(env) + [
'-v', f'{target_dir}:/out', '-t', BASE_RUNNER_IMAGE
'-v', f'{args.project.out}:/out', '-t', BASE_RUNNER_IMAGE
]
if args.fuzzer_name: