diff --git a/infra/base-images/base-builder-fuzzbench/fuzzbench_run_fuzzer b/infra/base-images/base-builder-fuzzbench/fuzzbench_run_fuzzer index 008fdbb05cc3..4df40d3e0e41 100755 --- a/infra/base-images/base-builder-fuzzbench/fuzzbench_run_fuzzer +++ b/infra/base-images/base-builder-fuzzbench/fuzzbench_run_fuzzer @@ -25,9 +25,7 @@ mkdir $SEED_CORPUS_DIR rm -rf $OUTPUT_CORPUS_DIR mkdir $OUTPUT_CORPUS_DIR export FUZZER=$FUZZING_ENGINE -# TODO(metzman): Make this configurable. -export MAX_TOTAL_TIME=120 -export SNAPSHOT_PERIOD=30 +export SNAPSHOT_PERIOD=900 export TRIAL_ID=1 export FORCE_LOCAL=1 diff --git a/infra/build/functions/fuzzbench.py b/infra/build/functions/fuzzbench.py index 0936cb6debe8..6cbecf5b92f9 100644 --- a/infra/build/functions/fuzzbench.py +++ b/infra/build/functions/fuzzbench.py @@ -19,10 +19,12 @@ import logging import os +import requests import sys import build_lib import build_project +import ood_upload_corpus INFRA_DIR = os.path.dirname( os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) @@ -33,6 +35,7 @@ FUZZBENCH_BUILD_TYPE = 'coverage' FUZZBENCH_PATH = '/fuzzbench' GCB_WORKSPACE_DIR = '/workspace' +MAX_FUZZING_DURATION = 1800 OOD_OUTPUT_CORPUS_DIR = f'{GCB_WORKSPACE_DIR}/ood_output_corpus' OOD_CRASHES_DIR = f'{GCB_WORKSPACE_DIR}/crashes' @@ -72,6 +75,22 @@ def get_latest_libfuzzer_build(project_name): return build_uri, latest_build_filename +def get_fuzz_target_name(project_name): + """Use Fuzz Introspector Web API to choose a fuzz target for |project_name|""" + header = {'accept': 'application/json'} + url = f'https://introspector.oss-fuzz.com/api/harness-source-and-executable?project={project_name}' + resp = requests.get(url, headers=header) + resp.raise_for_status() + resp_json = resp.json() + + if len(resp_json) < 1: + raise Exception(f'There are no fuzz targets available for {project_name}.') + + fuzz_target_name = resp_json['pairs'][0]['executable'] + logging.info(f'Using fuzz target: {fuzz_target_name}') + return fuzz_target_name + + def get_env(project, build, config): """Gets the environment for fuzzbench/oss-fuzz-on-demand.""" env = build_project.get_env(project.fuzzing_language, build) @@ -212,6 +231,7 @@ def get_build_ood_image_steps(fuzzing_engine, project, env_dict): image. Executing docker run on this image starts the fuzzing process.""" steps = [] + fuzzbench_run_fuzzer_path = f'{GCB_WORKSPACE_DIR}/oss-fuzz/infra/base-images/base-builder-fuzzbench/fuzzbench_run_fuzzer' copy_runtime_essential_files_step = { 'name': get_engine_project_image_name(fuzzing_engine, project), @@ -220,7 +240,7 @@ def get_build_ood_image_steps(fuzzing_engine, project, env_dict): 'path': FUZZBENCH_PATH, }], 'args': [ - 'bash', '-c', 'cp /usr/local/bin/fuzzbench_run_fuzzer ' + 'bash', '-c', f'cp {fuzzbench_run_fuzzer_path} ' f'{GCB_WORKSPACE_DIR}/fuzzbench_run_fuzzer.sh && ' f'cp -r {FUZZBENCH_PATH} {GCB_WORKSPACE_DIR} && ' f'ls {GCB_WORKSPACE_DIR}' @@ -255,6 +275,7 @@ def get_build_ood_image_steps(fuzzing_engine, project, env_dict): f'FUZZBENCH_PATH={FUZZBENCH_PATH}', '--build-arg', f'FUZZING_ENGINE={env_dict["FUZZING_ENGINE"]}', '--build-arg', f'FUZZ_TARGET={env_dict["FUZZ_TARGET"]}', '--build-arg', + f'MAX_TOTAL_TIME={MAX_FUZZING_DURATION}', '--build-arg', f'OOD_OUTPUT_CORPUS_DIR={OOD_OUTPUT_CORPUS_DIR}', '--build-arg', f'runtime_image={ood_image}', GCB_WORKSPACE_DIR ] @@ -365,6 +386,14 @@ def get_build_steps( # pylint: disable=too-many-locals, too-many-arguments logging.info('Project "%s" is disabled.', project.name) return [] + + if not config.fuzz_target: + config.fuzz_target = get_fuzz_target_name(project.name) + signed_urls = ood_upload_corpus.get_signed_upload_corpus_urls(project.name, + config.fuzz_target, + 3) + + steps = get_fuzzbench_setup_steps() steps += build_lib.get_project_image_steps(project.name, project.image, diff --git a/infra/build/functions/ood.Dockerfile b/infra/build/functions/ood.Dockerfile index 609a3938a381..bfd3152ad063 100644 --- a/infra/build/functions/ood.Dockerfile +++ b/infra/build/functions/ood.Dockerfile @@ -23,6 +23,7 @@ ARG FUZZING_ENGINE ARG FUZZ_TARGET ARG FUZZBENCH_PATH ARG BENCHMARK +ARG MAX_TOTAL_TIME ARG OOD_OUTPUT_CORPUS_DIR RUN mkdir -p /ood @@ -37,6 +38,7 @@ ENV FUZZING_ENGINE=$FUZZING_ENGINE ENV FUZZ_TARGET=$FUZZ_TARGET ENV FUZZBENCH_PATH=/ood$FUZZBENCH_PATH ENV BENCHMARK=$BENCHMARK +ENV MAX_TOTAL_TIME=$MAX_TOTAL_TIME ENV OOD_OUTPUT_CORPUS_DIR=$OOD_OUTPUT_CORPUS_DIR CMD ["bash", "-c", "source /ood/fuzzbench_run_fuzzer.sh && \ diff --git a/infra/build/functions/ood_upload_corpus.py b/infra/build/functions/ood_upload_corpus.py new file mode 100644 index 000000000000..5ecb6b967819 --- /dev/null +++ b/infra/build/functions/ood_upload_corpus.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +# +# Copyright 2025 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. +# +################################################################################ +""" """ +import logging +import sys +import uuid + +import build_lib + + +def get_upload_corpus_bucket(project_name, fuzz_target_name): + """ .""" + return (f'/{project_name}-corpus.clusterfuzz-external.appspot.com/' + f'libFuzzer/{fuzz_target_name}/') + + +def get_signed_upload_corpus_urls(project_name, fuzz_target_name, num_uploads): + """ .""" + upload_corpus_bucket = get_upload_corpus_bucket(project_name, + fuzz_target_name) + base_path = f'{upload_corpus_bucket}{uuid.uuid4().hex}' + + signed_urls = [] + #TODO: Make the following parallel + for idx in range(num_uploads): + path = f'{base_path}-{idx}' + signed_url = build_lib.get_signed_url(path) + signed_urls.append(signed_url) + + logging.info(signed_urls) + return signed_urls + + +def main(): + """Build and run locally fuzzbench for OSS-Fuzz projects.""" + project_name = 'skcms' + fuzz_target_name = 'iccprofile_atf' + get_signed_upload_corpus_urls(project_name, fuzz_target_name, 3) + + return 0 + + +if __name__ == '__main__': + sys.exit(main())