Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/new_library.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,12 @@ $ python scripts/helper.py run_fuzzer $LIB_NAME name_of_a_fuzzer
If everything works locally, then it should also work on our automated builders
and ClusterFuzz.

It's recommended to look at coverage as a sanity check to make sure that fuzzer gets to the code you expect.

```bash
$ sudo python scripts/helper.py coverage $LIB_NAME name_of_a_fuzzer
```

## Debugging Problems

[Debugging](debugging.md) document lists ways to debug your build scripts or fuzzers
Expand Down
3 changes: 3 additions & 0 deletions infra/base-images/Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,7 @@ node {

stage name: 'ossfuzz/libfuzzer-runner', concurrency: 1
sh "docker build $dockerOptions -t ossfuzz/libfuzzer-runner infra/base-images/libfuzzer-runner"

stage name: 'ossfuzz/coverage', concurrency: 1
sh "docker build $dockerOptions -t ossfuzz/coverage infra/base-images/coverage"
}
2 changes: 1 addition & 1 deletion infra/base-images/all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ docker build --pull -t ossfuzz/base $@ infra/base-images/base
docker build -t ossfuzz/base-clang $@ infra/base-images/base-clang
docker build -t ossfuzz/base-libfuzzer $@ infra/base-images/base-libfuzzer
docker build -t ossfuzz/libfuzzer-runner $@ infra/base-images/libfuzzer-runner

docker build -t ossfuzz/coverage $@ infra/base-images/coverage
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You will also need to change Jenkinsfile in this folder & Jenkinsfile in ../push-images/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

23 changes: 23 additions & 0 deletions infra/base-images/coverage/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright 2016 Google Inc.
#
# 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.
#
################################################################################

FROM ossfuzz/base-clang
MAINTAINER vitalybuka@gmail.com
RUN apt-get install -y python3 curl

RUN mkdir -p /src/coverage/
RUN cd /src/coverage/ && curl -O http://llvm.org/svn/llvm-project/llvm/trunk/tools/sancov/coverage-report-server.py && chmod +x coverage-report-server.py
COPY coverage /src/coverage/
24 changes: 24 additions & 0 deletions infra/base-images/coverage/coverage
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/bash -eu
# Copyright 2016 Google Inc.
#
# 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.
#
################################################################################

BINARY=$1

sancov -symbolize *.sancov -strip_path_prefix=/ $BINARY >> cov.symcov

(sleep 3; echo ; echo "Navigate to see coverage: http://127.0.0.1:8001/"; echo) &
/src/coverage/coverage-report-server.py --host 0.0.0.0 --symcov cov.symcov --srcpath /

65 changes: 62 additions & 3 deletions scripts/helper.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@
from __future__ import print_function
import argparse
import os
import re
import pipes
import re
import shutil
import subprocess
import sys

import tempfile
import templates
import time

OSSFUZZ_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
BUILD_DIR = os.path.join(OSSFUZZ_DIR, 'build')
Expand All @@ -38,7 +39,7 @@ def main():
parser = argparse.ArgumentParser('helper.py', description='oss-fuzz helpers')
parser.add_argument(
'command',
help='One of: generate, build_image, build_fuzzers, run_fuzzer, shell',
help='One of: generate, build_image, build_fuzzers, run_fuzzer, coverage, shell',
nargs=argparse.REMAINDER)
args = parser.parse_args()

Expand All @@ -54,6 +55,8 @@ def main():
return build_fuzzers(args.command[1:])
elif args.command[0] == 'run_fuzzer':
return run_fuzzer(args.command[1:])
elif args.command[0] == 'coverage':
return coverage(args.command[1:])
elif args.command[0] == 'shell':
return shell(args.command[1:])
else:
Expand Down Expand Up @@ -230,6 +233,62 @@ def run_fuzzer(run_args):
pipe = subprocess.Popen(command)
pipe.communicate()

def coverage(run_args):
"""Runs a fuzzer in the container."""
parser = argparse.ArgumentParser('helper.py coverage')
parser.add_argument('--run_time', default=60, help='time in seconds to run fuzzer')
parser.add_argument('library_name', help='name of the library')
parser.add_argument('fuzzer_name', help='name of the fuzzer')
parser.add_argument('fuzzer_args', help='arguments to pass to the fuzzer',
nargs=argparse.REMAINDER)
args = parser.parse_args(run_args)

if not _check_library_exists(args.library_name):
return 1

if not os.path.exists(os.path.join(BUILD_DIR, 'out', args.library_name,
args.fuzzer_name)):
print(args.fuzzer_name,
'does not seem to exist. Please run build_fuzzers first.',
file=sys.stderr)
return 1

temp_dir = tempfile.mkdtemp()
print (args.fuzzer_args)

command = [
'docker', 'run', '-i',
'-v', '%s:/out' % os.path.join(BUILD_DIR, 'out'),
'-v', '%s:/cov' % temp_dir,
'-w', '/cov',
'-e', 'ASAN_OPTIONS=coverage=1,detect_leaks=0',
'-t', 'ossfuzz/libfuzzer-runner',
'/out/%s/%s' % (args.library_name, args.fuzzer_name),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised by this additional directory. AFAIK our build scripts do not create second level.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what do you mean.

'-max_total_time=%s' % args.run_time
] + args.fuzzer_args

print('Running:', _get_command_string(command))
pipe = subprocess.Popen(command)
pipe.communicate()

checkout_dir = os.path.join(BUILD_DIR, args.library_name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't have to run it in docker. You can run all of it on host => no need to install in the image python.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe it's insecure to run random python script downloaded over http

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm...

Can you try running it within standard image? For example, one of these: https://hub.docker.com/_/python/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If not, let's create a special image for server. I am not keen on pulling new packages just for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

command = [
'docker', 'run', '-i',
'-v', '%s:/src/oss-fuzz' % OSSFUZZ_DIR,
'-v', '%s:/src/%s' % (checkout_dir, args.library_name),
'-v', '%s:/out' % os.path.join(BUILD_DIR, 'out', args.library_name),
'-v', '%s:/cov' % temp_dir,
'-v', '%s:/scripts' % os.path.join(OSSFUZZ_DIR, 'scripts'),
'-w', '/cov',
'-p', '8001:8001',
'-t', 'ossfuzz/coverage',
'/src/coverage/coverage', '/out/%s' % args.fuzzer_name,
]

print('Running:', _get_command_string(command))
pipe = subprocess.Popen(command)
pipe.communicate()


def generate(generate_args):
"""Generate empty library files."""
Expand Down
Empty file modified scripts/templates.py
100644 → 100755
Empty file.