mirror of https://github.com/google/oss-fuzz.git
95 lines
3.2 KiB
Python
95 lines
3.2 KiB
Python
# Copyright 2021 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 for running fuzzers."""
|
|
import logging
|
|
import os
|
|
import shutil
|
|
import sys
|
|
import time
|
|
|
|
import fuzz_target
|
|
import stack_parser
|
|
|
|
# pylint: disable=wrong-import-position,import-error
|
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
|
|
import utils
|
|
|
|
|
|
def run_fuzzers( # pylint: disable=too-many-arguments,too-many-locals
|
|
fuzz_seconds,
|
|
workspace,
|
|
project_name,
|
|
sanitizer='address'):
|
|
"""Runs all fuzzers for a specific OSS-Fuzz project.
|
|
|
|
Args:
|
|
fuzz_seconds: The total time allotted for fuzzing.
|
|
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).
|
|
"""
|
|
# Validate inputs.
|
|
if not os.path.exists(workspace):
|
|
logging.error('Invalid workspace: %s.', workspace)
|
|
return False, False
|
|
|
|
logging.info('Using %s sanitizer.', sanitizer)
|
|
|
|
out_dir = os.path.join(workspace, 'out')
|
|
artifacts_dir = os.path.join(out_dir, 'artifacts')
|
|
os.makedirs(artifacts_dir, exist_ok=True)
|
|
if not fuzz_seconds or fuzz_seconds < 1:
|
|
logging.error('Fuzz_seconds argument must be greater than 1, but was: %s.',
|
|
fuzz_seconds)
|
|
return False, False
|
|
|
|
# Get fuzzer information.
|
|
fuzzer_paths = utils.get_fuzz_targets(out_dir)
|
|
if not fuzzer_paths:
|
|
logging.error('No fuzzers were found in out directory: %s.', out_dir)
|
|
return False, False
|
|
|
|
# Run fuzzers for allotted time.
|
|
total_num_fuzzers = len(fuzzer_paths)
|
|
fuzzers_left_to_run = total_num_fuzzers
|
|
min_seconds_per_fuzzer = fuzz_seconds // total_num_fuzzers
|
|
for fuzzer_path in fuzzer_paths:
|
|
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,
|
|
sanitizer=sanitizer)
|
|
start_time = time.time()
|
|
testcase, stacktrace = target.fuzz()
|
|
fuzz_seconds -= (time.time() - start_time)
|
|
if not testcase or not stacktrace:
|
|
logging.info('Fuzzer %s, finished running.', target.target_name)
|
|
else:
|
|
utils.binary_print(b'Fuzzer %s, detected error:\n%s' %
|
|
(target.target_name.encode(), stacktrace))
|
|
shutil.move(testcase, os.path.join(artifacts_dir, 'test_case'))
|
|
stack_parser.parse_fuzzer_output(stacktrace, artifacts_dir)
|
|
return True, True
|
|
fuzzers_left_to_run -= 1
|
|
|
|
return True, False
|