Skip to content

Commit 6bc246b

Browse files
authored
target_experiment.py uploads reproducer and binary in target_experiment.py (#11700)
Helps google/oss-fuzz-gen#156: 1. `target_experiment.py` takes a new parameter, `upload_reproducer_path`. 2. `target_experiment.py` saves crash reproducer to `local_artifect_path`. 3. `target_experiment.py` uploads the fuzz target binary and the crash reproducer to bucket directory `upload_reproducer_path`.
1 parent 33c4a6d commit 6bc246b

File tree

1 file changed

+69
-3
lines changed

1 file changed

+69
-3
lines changed

infra/build/functions/target_experiment.py

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
def run_experiment(project_name, target_name, args, output_path,
3232
build_output_path, upload_corpus_path, upload_coverage_path,
33-
experiment_name):
33+
experiment_name, upload_reproducer_path):
3434
config = build_project.Config(testing=True,
3535
test_image_suffix='',
3636
repo=build_project.DEFAULT_OSS_FUZZ_REPO,
@@ -74,8 +74,12 @@ def run_experiment(project_name, target_name, args, output_path,
7474
local_output_path = '/workspace/output.log'
7575
local_corpus_path_base = '/workspace/corpus'
7676
local_corpus_path = os.path.join(local_corpus_path_base, target_name)
77+
default_target_path = os.path.join(build.out, target_name)
78+
local_target_dir = os.path.join(build.out, 'target')
7779
local_corpus_zip_path = '/workspace/corpus/corpus.zip'
78-
fuzzer_args = ' '.join(args)
80+
local_artifact_path = os.path.join(build.out, 'artifacts/')
81+
local_stacktrace_path = os.path.join(build.out, 'stacktrace/')
82+
fuzzer_args = ' '.join(args + [f'-artifact_prefix={local_artifact_path}'])
7983

8084
env = build_project.get_env(project_yaml['language'], build)
8185
env.append('RUN_FUZZER_MODE=batch')
@@ -90,6 +94,9 @@ def run_experiment(project_name, target_name, args, output_path,
9094
'bash',
9195
'-c',
9296
(f'mkdir -p {local_corpus_path} && '
97+
f'mkdir -p {local_target_dir} && '
98+
f'mkdir -p {local_artifact_path} && '
99+
f'mkdir -p {local_stacktrace_path} && '
93100
f'run_fuzzer {target_name} {fuzzer_args} '
94101
f'|& tee {local_output_path} || true'),
95102
]
@@ -115,6 +122,60 @@ def run_experiment(project_name, target_name, args, output_path,
115122
],
116123
})
117124

125+
if upload_reproducer_path:
126+
# Upload binary. First copy the binary directly from default_target_path,
127+
# if that fails, find it under build out dir and copy to local_target_dir.
128+
# If either succeeds, then upload it to bucket.
129+
# If multiple files are found, suffix them and upload them all.
130+
steps.append({
131+
'name':
132+
'gcr.io/cloud-builders/gsutil',
133+
'entrypoint':
134+
'/bin/bash',
135+
'args': [
136+
'-c',
137+
(f'cp {default_target_path} {local_target_dir} 2>/dev/null || '
138+
f'find {build.out} -type f -name {target_name} -exec bash -c '
139+
f'\'cp "$0" "{local_target_dir}/$(echo "$0" | sed "s@/@_@g")"\' '
140+
f'{{}} \\; && gsutil cp -r {local_target_dir} '
141+
f'{upload_reproducer_path}/{target_name} || true'),
142+
],
143+
})
144+
145+
# Upload reproducer.
146+
steps.append({
147+
'name':
148+
'gcr.io/cloud-builders/gsutil',
149+
'entrypoint':
150+
'/bin/bash',
151+
'args': [
152+
'-c',
153+
(f'gsutil -m cp -r {local_artifact_path} {upload_reproducer_path} '
154+
'|| true'),
155+
],
156+
})
157+
158+
# Upload stacktrace.
159+
steps.append({
160+
'name':
161+
'gcr.io/cloud-builders/gsutil',
162+
'entrypoint':
163+
'/bin/bash',
164+
'args': [
165+
'-c',
166+
(f'if [ -f {local_target_dir}/{target_name} ]; then '
167+
f'{local_target_dir}/{target_name} {local_artifact_path}/* > '
168+
f'{local_stacktrace_path}/{target_name}.st 2>&1; '
169+
'else '
170+
f'for target in {local_target_dir}/*; do '
171+
f'"$target" {local_artifact_path}/* > '
172+
f'"{local_stacktrace_path}/$target.st" 2>&1; '
173+
'done; fi; '
174+
f'gsutil -m cp -r {local_stacktrace_path} {upload_reproducer_path}'
175+
' || true'),
176+
],
177+
})
178+
118179
# Build for coverage.
119180
build = build_project.Build('libfuzzer', 'coverage', 'x86_64')
120181
env = build_project.get_env(project_yaml['language'], build)
@@ -213,6 +274,10 @@ def main():
213274
parser.add_argument('--upload_corpus',
214275
required=True,
215276
help='GCS location to upload corpus.')
277+
parser.add_argument('--upload_reproducer',
278+
required=False,
279+
default='',
280+
help='GCS location to upload reproducer.')
216281
parser.add_argument('--upload_coverage',
217282
required=True,
218283
help='GCS location to upload coverage data.')
@@ -223,7 +288,8 @@ def main():
223288

224289
run_experiment(args.project, args.target, args.args, args.upload_output_log,
225290
args.upload_build_log, args.upload_corpus,
226-
args.upload_coverage, args.experiment_name)
291+
args.upload_coverage, args.experiment_name,
292+
args.upload_reproducer)
227293

228294

229295
if __name__ == '__main__':

0 commit comments

Comments
 (0)