oss-fuzz/infra/cifuzz/cifuzz.py

153 lines
5.3 KiB
Python
Raw Normal View History

[Infra] CIFuzz pipeline complete. (#3281) * Testing action build * Testing action build * Testing action build * Testing action build * Testing action build * Testing action build * Testing action build * Testing action build * Testing action build * Testing action build * Testing action build * Testing action build * Testing action build * Testing action build * Testing action build * Testing action build * Testing action build * Testing action build * Testing action build * Testing action build * Testing action build * Working build * Working build * Working build * Working build * Working build * Working build * Working build * Working build * Working build * Working build * Working build * Working build * Working build * Working build * Working build * Working build * Working build * Working build * Working build * Working build * Working build * Working build * Working build * Working build * Working build * Working build * Working fuzzers with out error surface * Working fuzzers with out error surface * Working fuzzers with out error surface * Printing std err * Adding fuzzer timeout * Adding fuzzer timeout * Changing fuzzer timeout to fuzz time * Formatting and refactoring * Spelling in fuzz_target.py * Spelling in fuzz_target.py * Spelling in fuzz_target.py * Upload artifact fix * Upload artifact fix * Upload artifact fix * Upload artifact fix * Upload artifact fix * Upload artifact fix * Upload artifact fix * Refactoring error codes. * reverting helper.py * reverting helper.py * reverting helper.py * chaning method to static * moving cifuzz file * Jonathan changes * Oliver and Jonathan comments * Oliver and Jonathan comments * Oliver and Jonathan comments * Utils unit tests * Test formatting and documentation * Build fuzzer test added * Changed repo manager errors * Unit and integration tests complete * Jonathan comments pt.1 * Jonathan comments pt.1 * Jonathan comments pt.1 * adding cifuzz_test * Build fuzzer test completed * Run fuzzers test finished. * Removed SRC dependency * Jonathan comments pt.2 * Max comments pt.1 * Max comments pt.2 * removing log specified out stream * Max comments pt.3 * Adding OSS_FUZZ_HOME env var * Jonathan comments pt.3 * Formatting * Olivers comments * Jonathan comments
2020-01-29 19:03:43 +00:00
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Module used by CI tools in order to interact with fuzzers.
This module helps CI tools do the following:
1. Build fuzzers.
2. Run fuzzers.
Eventually it will be used to help CI tools determine which fuzzers to run.
"""
import logging
import os
import shutil
import sys
import fuzz_target
# pylint: disable=wrong-import-position
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import build_specified_commit
import helper
import repo_manager
import utils
# TODO: Turn default logging to WARNING when CIFuzz is stable
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.DEBUG)
def build_fuzzers(project_name, project_repo_name, commit_sha, git_workspace,
out_dir):
"""Builds all of the fuzzers for a specific OSS-Fuzz project.
Args:
project_name: The name of the OSS-Fuzz project being built.
project_repo_name: The name of the projects repo.
commit_sha: The commit SHA to be checked out and fuzzed.
git_workspace: The location in the shared volume to store git repos.
out_dir: The location in the shared volume to store output artifacts.
Returns:
True if build succeeded or False on failure.
"""
if not os.path.exists(git_workspace):
logging.error('Invalid git workspace: %s.', format(git_workspace))
return False
if not os.path.exists(out_dir):
logging.error('Invalid out directory %s.', format(out_dir))
return False
inferred_url, oss_fuzz_repo_path = build_specified_commit.detect_main_repo(
project_name, repo_name=project_repo_name)
if not inferred_url or not oss_fuzz_repo_path:
logging.error('Could not detect repo from project %s.', project_name)
return False
src_in_docker = os.path.dirname(oss_fuzz_repo_path)
oss_fuzz_repo_name = os.path.basename(oss_fuzz_repo_path)
# Checkout projects repo in the shared volume.
build_repo_manager = repo_manager.RepoManager(inferred_url,
git_workspace,
repo_name=oss_fuzz_repo_name)
try:
build_repo_manager.checkout_commit(commit_sha)
except repo_manager.RepoManagerError:
logging.error('Specified commit does not exist.')
# NOTE: Remove return statement for testing.
return False
command = [
'--cap-add', 'SYS_PTRACE', '-e', 'FUZZING_ENGINE=libfuzzer', '-e',
'SANITIZER=address', '-e', 'ARCHITECTURE=x86_64'
]
container = utils.get_container_name()
if container:
command += ['-e', 'OUT=' + out_dir, '--volumes-from', container]
bash_command = 'rm -rf {0} && cp -r {1} {2} && compile'.format(
os.path.join(src_in_docker, oss_fuzz_repo_name, '*'),
os.path.join(git_workspace, oss_fuzz_repo_name), src_in_docker)
else:
command += [
'-e', 'OUT=' + '/out', '-v',
'%s:%s' % (os.path.join(git_workspace, oss_fuzz_repo_name),
os.path.join(src_in_docker, oss_fuzz_repo_name)), '-v',
'%s:%s' % (out_dir, '/out')
]
bash_command = 'compile'
command.extend([
'gcr.io/oss-fuzz/' + project_name,
'/bin/bash',
'-c',
])
command.append(bash_command)
if helper.docker_run(command):
logging.error('Building fuzzers failed.')
return False
return True
def run_fuzzers(project_name, fuzz_seconds, out_dir):
"""Runs all fuzzers for a specific OSS-Fuzz project.
Args:
project_name: The name of the OSS-Fuzz project being built.
fuzz_seconds: The total time allotted for fuzzing.
out_dir: The location in the shared volume to store output artifacts.
Returns:
(True if run was successful, True if bug was found).
"""
if not out_dir or not os.path.exists(out_dir):
logging.error('Unreachable out_dir argument %s.', format(out_dir))
return False, False
if not fuzz_seconds or fuzz_seconds < 1:
logging.error('Fuzz_seconds argument must be greater than 1, but was: %s.',
format(fuzz_seconds))
return False, False
fuzzer_paths = utils.get_fuzz_targets(out_dir)
if not fuzzer_paths:
logging.error('No fuzzers were found in out directory: %s.',
format(out_dir))
return False, False
fuzz_seconds_per_target = fuzz_seconds // len(fuzzer_paths)
for fuzzer_path in fuzzer_paths:
target = fuzz_target.FuzzTarget(project_name, fuzzer_path,
fuzz_seconds_per_target, out_dir)
test_case, stack_trace = target.fuzz()
if not test_case or not stack_trace:
logging.info('Fuzzer %s, finished running.', target.target_name)
else:
logging.info('Fuzzer %s, detected error: %s.', target.target_name,
stack_trace)
shutil.move(test_case, os.path.join(out_dir, 'testcase'))
return True, True
return True, False