Skip to content

Commit bb95bc3

Browse files
authored
Build OSS-Fuzz projects with FuzzBench fuzzers. (#13126)
Use fuzzbench.py for building OSS-Fuzz projects with FuzzBench fuzzers. - Added a call to `fuzzbench.py`'s `get_build_steps` function in the `oss_fuzz_on_demand.py` main function. - Changed `FUZZ_TARGET` environment variable value to an empty string to be able to find binary targets during the build. - Added handling of command line arguments. - Removed `OUT` environment variable overwrite on `fuzzbench.py` to make code more understandable. Related to b/401215144 .
1 parent cdc5634 commit bb95bc3

File tree

6 files changed

+75
-45
lines changed

6 files changed

+75
-45
lines changed

infra/build/functions/build_project.py

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class Config:
7676
# TODO(ochang): This should be different per engine+sanitizer combination.
7777
upload_build_logs: str = None
7878
build_type: str = None
79+
fuzzing_engine: str = None
7980

8081

8182
# Allow the WORKDIR to be commented out for OSS-Fuzz-Gen, which creates new
@@ -607,9 +608,9 @@ def run_build(oss_fuzz_project,
607608
experiment=experiment)
608609

609610

610-
def get_args(description):
611-
"""Parses command line arguments and returns them. Suitable for a build
612-
script."""
611+
def parse_args(description, args):
612+
"""Parses command line arguments (or args if it is not None) and returns them.
613+
Suitable for a build script."""
613614
parser = argparse.ArgumentParser(sys.argv[0], description=description)
614615
parser.add_argument('projects', help='Projects.', nargs='+')
615616
parser.add_argument('--testing',
@@ -621,6 +622,10 @@ def get_args(description):
621622
required=False,
622623
default=None,
623624
help='Use testing base-images.')
625+
parser.add_argument('--repo',
626+
required=False,
627+
default=DEFAULT_OSS_FUZZ_REPO,
628+
help='Use specified OSS-Fuzz repo.')
624629
parser.add_argument('--branch',
625630
required=False,
626631
default=None,
@@ -635,7 +640,11 @@ def get_args(description):
635640
required=False,
636641
default=False,
637642
help='Configuration for experiments.')
638-
return parser.parse_args()
643+
parser.add_argument('--fuzzing-engine',
644+
required=False,
645+
default='libfuzzer',
646+
help='Fuzzing engine name.')
647+
return parser.parse_args(args)
639648

640649

641650
def create_config(args, build_type):
@@ -647,15 +656,19 @@ def create_config(args, build_type):
647656
parallel=args.parallel,
648657
upload=upload,
649658
experiment=args.experiment,
650-
build_type=build_type)
659+
build_type=build_type,
660+
fuzzing_engine=args.fuzzing_engine)
651661

652662

653-
def build_script_main(script_description, get_build_steps_func, build_type):
663+
def build_script_main(script_description,
664+
get_build_steps_func,
665+
build_type,
666+
args=None):
654667
"""Gets arguments from command line using |script_description| as helpstring
655-
description. Gets build_steps using |get_build_steps_func| and then runs those
656-
steps on GCB, tagging the builds with |build_type|. Returns 0 on success, 1 on
657-
failure."""
658-
args = get_args(script_description)
668+
description or from args. Gets build_steps using |get_build_steps_func| and
669+
then runs those steps on GCB, tagging the builds with |build_type|. Returns 0
670+
on success, 1 on failure."""
671+
args = parse_args(script_description, args)
659672
logging.basicConfig(level=logging.INFO)
660673

661674
credentials = oauth2client.client.GoogleCredentials.get_application_default()

infra/build/functions/fuzzbench.py

Lines changed: 14 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,8 @@ def get_env(project, build):
4141
env.append('FORCE_LOCAL=1')
4242
env.append(f'PROJECT={project.name}')
4343
env.append('OSS_FUZZ_ON_DEMAND=1')
44-
env.append('OUT=/workspace/out')
45-
env.extend([
46-
'FUZZ_TARGET=vulnerable', f'BENCHMARK={project.name}',
47-
'EXPERIMENT_TYPE=bug'
48-
])
44+
env.extend(
45+
['FUZZ_TARGET=', f'BENCHMARK={project.name}', 'EXPERIMENT_TYPE=bug'])
4946
return env
5047

5148

@@ -98,21 +95,19 @@ def get_build_fuzzers_step(fuzzing_engine, project, env, build):
9895

9996

10097
def get_build_steps( # pylint: disable=too-many-locals, too-many-arguments
101-
project_name, project_yaml, dockerfile_lines, image_project,
102-
base_images_project, config):
98+
project_name, project_yaml, dockerfile_lines, config):
10399
"""Returns build steps for project."""
104-
del base_images_project
105-
project = build_project.Project(project_name, project_yaml, dockerfile_lines,
106-
image_project)
100+
project = build_project.Project(project_name, project_yaml, dockerfile_lines)
107101
if project.disabled:
108102
logging.info('Project "%s" is disabled.', project.name)
109103
return []
110104

111-
config = build_project.Config(config.testing, None, config.repo,
112-
config.branch, config.parallel, config.upload)
113-
114-
# TODO(metzman): Make this a command line argument
115-
fuzzing_engine = 'libfuzzer'
105+
config = build_project.Config(testing=config.testing,
106+
repo=config.repo,
107+
branch=config.branch,
108+
parallel=config.parallel,
109+
upload=config.upload,
110+
fuzzing_engine=config.fuzzing_engine)
116111

117112
steps = [
118113
{
@@ -145,13 +140,14 @@ def get_build_steps( # pylint: disable=too-many-locals, too-many-arguments
145140
project.fuzzing_language,
146141
config=config)
147142

148-
build = build_project.Build(fuzzing_engine, 'address', 'x86_64')
143+
build = build_project.Build(config.fuzzing_engine, 'address', 'x86_64')
149144
env = get_env(project, build)
150145

151-
steps += get_build_fuzzers_step(fuzzing_engine, project, env, build)
146+
steps += get_build_fuzzers_step(config.fuzzing_engine, project, env, build)
147+
152148
run_fuzzer_step = {
153149
'name':
154-
get_engine_project_image(fuzzing_engine, project),
150+
get_engine_project_image(config.fuzzing_engine, project),
155151
'env':
156152
env,
157153
'volumes': [{
@@ -166,20 +162,6 @@ def get_build_steps( # pylint: disable=too-many-locals, too-many-arguments
166162
],
167163
}
168164
steps.append(run_fuzzer_step)
169-
170-
build = build_project.Build('coverage', 'address', 'x86_64')
171-
env = get_env(project, build)
172-
env.append(f'FUZZER={fuzzing_engine}')
173-
steps += get_build_fuzzers_step('coverage', project, env, build)
174-
steps += [{
175-
'args': ['fuzzbench_measure'],
176-
'env': env,
177-
'name': get_engine_project_image('coverage', project),
178-
'volumes': [{
179-
'name': 'fuzzbench_path',
180-
'path': FUZZBENCH_PATH,
181-
}],
182-
}]
183165
return steps
184166

185167

infra/build/functions/gcb.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ def get_latest_gcbrun_command(comments):
6767

6868
def exec_command_from_github(pull_request_number, repo, branch):
6969
"""Executes the gcbrun command for trial_build.py or oss_fuzz_on_demand.py in
70-
the most recent command on |pull_request_number|."""
70+
the most recent command on |pull_request_number|. Returns True on success,
71+
False on failure."""
7172
comments = get_comments(pull_request_number)
7273
full_command = get_latest_gcbrun_command(comments)
7374

@@ -85,7 +86,7 @@ def exec_command_from_github(pull_request_number, repo, branch):
8586
logging.info('Command: %s.', command)
8687

8788
if command_file == OSS_FUZZ_ON_DEMAND_COMMAND_STR.split(' ')[1]:
88-
return oss_fuzz_on_demand.oss_fuzz_on_demand_main(command)
89+
return oss_fuzz_on_demand.oss_fuzz_on_demand_main(command) == 0
8990
return trial_build.trial_build_main(command, local_base_build=False)
9091

9192

infra/build/functions/gcb_test.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,29 @@ def test_exec_command(self):
131131
mock_trial_build_trial_build_main.assert_not_called()
132132
mock_oss_fuzz_on_demand.assert_called_once_with(
133133
test_case["expected_command"])
134+
135+
@mock.patch('gcb.get_comments',
136+
return_value=[('/gcbrun oss_fuzz_on_demand.py aiohttp --sanitizer'
137+
'coverage address --fuzzing-engine libfuzzer')])
138+
@mock.patch('gcb.get_latest_gcbrun_command',
139+
return_value=[
140+
'oss_fuzz_on_demand.py', 'aiohttp', '--fuzzing-engine',
141+
'libfuzzer'
142+
])
143+
@mock.patch('trial_build.trial_build_main')
144+
@mock.patch('build_project.build_script_main', return_value=0)
145+
def test_build_script_main_args(self, mock_build_script_main,
146+
mock_trial_build_main,
147+
mock_get_latest_gcbrun_command,
148+
mock_gcb_get_comments):
149+
"""Tests for build_script_main args on oss_fuzz_on_demmand call."""
150+
gcb.exec_command_from_github(0, "test_repo", "test_branch")
151+
152+
mock_trial_build_main.assert_not_called()
153+
154+
build_script_main_args = [
155+
'aiohttp', '--fuzzing-engine', 'libfuzzer', '--repo', 'test_repo',
156+
'--branch', 'test_branch'
157+
]
158+
mock_build_script_main.assert_called_once_with(mock.ANY, mock.ANY, mock.ANY,
159+
build_script_main_args)

infra/build/functions/oss_fuzz_on_demand.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,16 @@
1818
import sys
1919
import logging
2020

21+
import fuzzbench
22+
import build_project
23+
2124

2225
def oss_fuzz_on_demand_main(args=None):
23-
"""Main function for OSS-Fuzz on demand."""
26+
"""Main function for OSS-Fuzz on demand. Returns 0 on success, 1 on
27+
failure."""
28+
return build_project.build_script_main('Does a FuzzBench run.',
29+
fuzzbench.get_build_steps,
30+
fuzzbench.FUZZBENCH_BUILD_TYPE, args)
2431

2532

2633
def main():

infra/build/functions/trial_build/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ COPY . /opt/oss-fuzz
2121
RUN pip install -r /opt/oss-fuzz/infra/build/functions/requirements.txt
2222

2323
WORKDIR /opt/oss-fuzz/infra/build/functions/
24+
2425
ENTRYPOINT ["python3", "/opt/oss-fuzz/infra/build/functions/gcb.py"]

0 commit comments

Comments
 (0)