• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2020 Google LLC
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#      http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Utilities for OSS-Fuzz infrastructure."""
15
16import os
17import re
18import stat
19import subprocess
20
21import helper
22
23ALLOWED_FUZZ_TARGET_EXTENSIONS = ['', '.exe']
24FUZZ_TARGET_SEARCH_STRING = 'LLVMFuzzerTestOneInput'
25VALID_TARGET_NAME = re.compile(r'^[a-zA-Z0-9_-]+$')
26
27
28def chdir_to_root():
29  """Changes cwd to OSS-Fuzz root directory."""
30  # Change to oss-fuzz main directory so helper.py runs correctly.
31  if os.getcwd() != helper.OSSFUZZ_DIR:
32    os.chdir(helper.OSSFUZZ_DIR)
33
34
35def execute(command, location=None, check_result=False):
36  """ Runs a shell command in the specified directory location.
37
38  Args:
39    command: The command as a list to be run.
40    location: The directory the command is run in.
41    check_result: Should an exception be thrown on failed command.
42
43  Returns:
44    The stdout of the command, the error code.
45
46  Raises:
47    RuntimeError: running a command resulted in an error.
48  """
49
50  if not location:
51    location = os.getcwd()
52  process = subprocess.Popen(command, stdout=subprocess.PIPE, cwd=location)
53  out, err = process.communicate()
54  if check_result and (process.returncode or err):
55    raise RuntimeError('Error: %s\n Command: %s\n Return code: %s\n Out: %s' %
56                       (err, command, process.returncode, out))
57  if out is not None:
58    out = out.decode('ascii').rstrip()
59  return out, process.returncode
60
61
62def get_fuzz_targets(path):
63  """Get list of fuzz targets in a directory.
64
65  Args:
66    path: A path to search for fuzz targets in.
67
68  Returns:
69    A list of paths to fuzzers or an empty list if None.
70  """
71  if not os.path.exists(path):
72    return []
73  fuzz_target_paths = []
74  for root, _, _ in os.walk(path):
75    for filename in os.listdir(path):
76      file_path = os.path.join(root, filename)
77      if is_fuzz_target_local(file_path):
78        fuzz_target_paths.append(file_path)
79
80  return fuzz_target_paths
81
82
83def get_container_name():
84  """Gets the name of the current docker container you are in.
85  /proc/self/cgroup can be used to check control groups e.g. Docker.
86  See: https://docs.docker.com/config/containers/runmetrics/ for more info.
87
88  Returns:
89    Container name or None if not in a container.
90  """
91  with open('/proc/self/cgroup') as file_handle:
92    if 'docker' not in file_handle.read():
93      return None
94  with open('/etc/hostname') as file_handle:
95    return file_handle.read().strip()
96
97
98def is_fuzz_target_local(file_path):
99  """Returns whether |file_path| is a fuzz target binary (local path).
100  Copied from clusterfuzz src/python/bot/fuzzers/utils.py
101  with slight modifications.
102  """
103  filename, file_extension = os.path.splitext(os.path.basename(file_path))
104  if not VALID_TARGET_NAME.match(filename):
105    # Check fuzz target has a valid name (without any special chars).
106    return False
107
108  if file_extension not in ALLOWED_FUZZ_TARGET_EXTENSIONS:
109    # Ignore files with disallowed extensions (to prevent opening e.g. .zips).
110    return False
111
112  if not os.path.exists(file_path) or not os.access(file_path, os.X_OK):
113    return False
114
115  if filename.endswith('_fuzzer'):
116    return True
117
118  if os.path.exists(file_path) and not stat.S_ISREG(os.stat(file_path).st_mode):
119    return False
120
121  with open(file_path, 'rb') as file_handle:
122    return file_handle.read().find(FUZZ_TARGET_SEARCH_STRING.encode()) != -1
123