예제 #1
0
  def test_build_fuzzers_from_commit(self):
    """Tests if the fuzzers can build at a specified commit.

    This is done by using a known regression range for a specific test case.
    The old commit should show the error when its fuzzers run and the new one
    should not.
    """
    with tempfile.TemporaryDirectory() as tmp_dir:
      test_case = test_repos.TEST_REPOS[1]
      self.assertTrue(helper.build_image_impl(test_case.project_name))
      host_src_dir = build_specified_commit.copy_src_from_docker(
          test_case.project_name, tmp_dir)

      test_repo_manager = repo_manager.clone_repo_and_get_manager(
          test_case.git_url, host_src_dir, test_case.oss_repo_name)
      build_data = build_specified_commit.BuildData(
          sanitizer='address',
          architecture='x86_64',
          engine='libfuzzer',
          project_name=test_case.project_name)

      build_specified_commit.build_fuzzers_from_commit(test_case.old_commit,
                                                       test_repo_manager,
                                                       host_src_dir, build_data)
      old_error_code = helper.reproduce_impl(test_case.project_name,
                                             test_case.fuzz_target, False, [],
                                             [], test_case.test_case_path)
      build_specified_commit.build_fuzzers_from_commit(test_case.new_commit,
                                                       test_repo_manager,
                                                       host_src_dir, build_data)
      new_error_code = helper.reproduce_impl(test_case.project_name,
                                             test_case.fuzz_target, False, [],
                                             [], test_case.test_case_path)
      self.assertNotEqual(new_error_code, old_error_code)
예제 #2
0
def build_fuzzers_from_commit(commit, build_repo_manager, host_src_path,
                              build_data):
  """Builds a OSS-Fuzz fuzzer at a specific commit SHA.

  Args:
    commit: The commit SHA to build the fuzzers at.
    build_repo_manager: The OSS-Fuzz project's repo manager to be built at.
    build_data: A struct containing project build information.
  Returns:
    0 on successful build or error code on failure.
  """
  oss_fuzz_repo_manager = repo_manager.BaseRepoManager(helper.OSS_FUZZ_DIR)
  num_retry = 1

  for i in range(num_retry + 1):
    build_repo_manager.checkout_commit(commit, clean=False)
    result = helper.build_fuzzers_impl(project_name=build_data.project_name,
                                       clean=True,
                                       engine=build_data.engine,
                                       sanitizer=build_data.sanitizer,
                                       architecture=build_data.architecture,
                                       env_to_add=None,
                                       source_path=host_src_path,
                                       mount_location='/src')
    if result == 0 or i == num_retry:
      break

    # Retry with an OSS-Fuzz builder container that's closer to the project
    # commit date.
    commit_date = build_repo_manager.commit_date(commit)
    projects_dir = os.path.join('projects', build_data.project_name)

    # Find first change in the projects/<PROJECT> directory before the project
    # commit date.
    oss_fuzz_commit, _, _ = oss_fuzz_repo_manager.git([
        'log', '--before=' + commit_date.isoformat(), '-n1', '--format=%H',
        projects_dir
    ],
                                                      check_result=True)
    oss_fuzz_commit = oss_fuzz_commit.strip()
    if not oss_fuzz_commit:
      logging.warning('No suitable earlier OSS-Fuzz commit found.')
      break

    logging.info('Build failed. Retrying on earlier OSS-Fuzz commit %s.',
                 oss_fuzz_commit)

    # Check out projects/<PROJECT> dir to the commit that was found.
    oss_fuzz_repo_manager.git(['checkout', oss_fuzz_commit, projects_dir],
                              check_result=True)

    # Rebuild image and re-copy src dir since things in /src could have changed.
    if not helper.build_image_impl(build_data.project_name):
      raise RuntimeError('Failed to rebuild image.')

    shutil.rmtree(host_src_path, ignore_errors=True)
    copy_src_from_docker(build_data.project_name,
                         os.path.dirname(host_src_path))

  return result == 0
예제 #3
0
 def test_oss_fuzz_project(self, mock_docker_build):
   """Tests that build_image_impl works as intended with an OSS-Fuzz
   project."""
   project_name = 'example'
   self.assertTrue(helper.build_image_impl(helper.Project(project_name)))
   build_dir = os.path.join(helper.OSS_FUZZ_DIR, 'projects', project_name)
   mock_docker_build.assert_called_with([
       '-t', 'gcr.io/oss-fuzz/example', '--file',
       os.path.join(build_dir, 'Dockerfile'), build_dir
   ])
예제 #4
0
 def test_base_image(self, mock_docker_build):
   """Tests that build_image_impl works as intended with a base-image."""
   image_name = 'base-image'
   self.assertTrue(helper.build_image_impl(helper.Project(image_name)))
   build_dir = os.path.join(helper.OSS_FUZZ_DIR,
                            'infra/base-images/base-image')
   mock_docker_build.assert_called_with([
       '-t', 'gcr.io/oss-fuzz-base/base-image', '--file',
       os.path.join(build_dir, 'Dockerfile'), build_dir
   ])
예제 #5
0
def detect_main_repo(project_name,
                     repo_name=None,
                     commit=None,
                     src_dir='/src'):
    """Checks a docker image for the main repo of an OSS-Fuzz project.

  Note: The default is to use the repo name to detect the main repo.

  Args:
    project_name: The name of the oss-fuzz project.
    repo_name: The name of the main repo in an OSS-Fuzz project.
    commit: A commit SHA that is associated with the main repo.
    src_dir: The location of the projects source on the docker image.

  Returns:
    The repo's origin, the repo's name.
  """
    # TODO: Add infra for non hardcoded '/src'.
    if not repo_name and not commit:
        print(
            'Error: can not detect main repo without a repo_name or a commit.')
        return None, None
    if repo_name and commit:
        print(
            'Both repo name and commit specific. Using repo name for detection.'
        )

    helper.build_image_impl(project_name)
    docker_image_name = 'gcr.io/oss-fuzz/' + project_name
    command_to_run = [
        'docker', 'run', '--rm', '-t', docker_image_name, 'python3',
        os.path.join(src_dir, 'detect_repo.py'), '--src_dir', src_dir
    ]
    if repo_name:
        command_to_run.extend(['--repo_name', repo_name])
    else:
        command_to_run.extend(['--example_commit', commit])
    out, _ = execute(command_to_run)
    match = re.search(r'\bDetected repo: ([^ ]+) ([^ ]+)', out.rstrip())
    if match and match.group(1) and match.group(2):
        return match.group(1), match.group(2)
    return None, None
예제 #6
0
def _build_image_with_retries(project_name):
    """Build image with retries."""

    for _ in range(_IMAGE_BUILD_TRIES):
        result = helper.build_image_impl(project_name)
        if result:
            return result

        time.sleep(_IMAGE_BUILD_RETRY_SLEEP)

    return result
예제 #7
0
def detect_main_repo_from_docker(project_name, example_commit, src_dir='/src'):
    """Checks a docker image for the main repo of an OSS-Fuzz project.

  Args:
    project_name: The name of the OSS-Fuzz project
    example_commit: An associated commit SHA
    src_dir: The location of the projects source on the docker image

  Returns:
    The repo's origin, the repo's name
  """
    helper.build_image_impl(project_name)
    docker_image_name = 'gcr.io/oss-fuzz/' + project_name
    command_to_run = [
        'docker', 'run', '--rm', '-i', '-t', docker_image_name, 'python3',
        os.path.join(src_dir, 'detect_repo.py'), '--src_dir', src_dir,
        '--example_commit', example_commit
    ]
    out, _ = execute(command_to_run)

    match = re.search(r'\bDetected repo: ([^ ]+) ([^ ]+)', out.rstrip())
    if match and match.group(1) and match.group(2):
        return match.group(1), match.group(2).rstrip()
    return None, None
예제 #8
0
 def test_external_project(self, mock_docker_build):
   """Tests that build_image_impl works as intended with a non-OSS-Fuzz
   project."""
   with tempfile.TemporaryDirectory() as temp_dir:
     project_src_path = os.path.join(temp_dir, 'example')
     os.mkdir(project_src_path)
     build_integration_path = 'build-integration'
     project = helper.Project(project_src_path,
                              is_external=True,
                              build_integration_path=build_integration_path)
     self.assertTrue(helper.build_image_impl(project))
     mock_docker_build.assert_called_with([
         '-t', 'gcr.io/oss-fuzz/example', '--file',
         os.path.join(project_src_path, build_integration_path, 'Dockerfile'),
         project_src_path
     ])
예제 #9
0
def detect_main_repo(project_name, repo_name=None, commit=None):
    """Checks a docker image for the main repo of an OSS-Fuzz project.

  Note: The default is to use the repo name to detect the main repo.

  Args:
    project_name: The name of the oss-fuzz project.
    repo_name: The name of the main repo in an OSS-Fuzz project.
    commit: A commit SHA that is associated with the main repo.
    src_dir: The location of the projects source on the docker image.

  Returns:
    The repo's origin, the repo's path.
  """

    if not repo_name and not commit:
        logging.error(
            'Error: can not detect main repo without a repo_name or a commit.')
        return None, None
    if repo_name and commit:
        logging.info(
            'Both repo name and commit specific. Using repo name for detection.'
        )

    # Change to oss-fuzz main directory so helper.py runs correctly.
    utils.chdir_to_root()
    if not helper.build_image_impl(project_name):
        logging.error('Error: building %s image failed.', project_name)
        return None, None
    docker_image_name = 'gcr.io/oss-fuzz/' + project_name
    command_to_run = [
        'docker', 'run', '--rm', '-t', docker_image_name, 'python3',
        os.path.join('/opt', 'cifuzz', 'detect_repo.py')
    ]
    if repo_name:
        command_to_run.extend(['--repo_name', repo_name])
    else:
        command_to_run.extend(['--example_commit', commit])
    out, _, _ = utils.execute(command_to_run)
    match = re.search(r'\bDetected repo: ([^ ]+) ([^ ]+)', out.rstrip())
    if match and match.group(1) and match.group(2):
        return match.group(1), match.group(2)

    logging.error('Failed to detect repo:\n%s', out)
    return None, None
예제 #10
0
def _build_image_with_retries(project_name):
  """Build image with retries."""
  return helper.build_image_impl(project_name)
예제 #11
0
 def test_pull(self, mock_pull_images, _):
   """Tests that pull=True is handled properly."""
   image_name = 'base-image'
   project = helper.Project(image_name, is_external=True)
   self.assertTrue(helper.build_image_impl(project, pull=True))
   mock_pull_images.assert_called_with('c++')
예제 #12
0
 def test_no_cache(self, mock_docker_build):
   """Tests that cache=False is handled properly."""
   image_name = 'base-image'
   helper.build_image_impl(helper.Project(image_name), cache=False)
   self.assertIn('--no-cache', mock_docker_build.call_args_list[0][0][0])
예제 #13
0
 def test_pull(self, mock_pull_images, _):
   """Tests that pull=True is handled properly."""
   image_name = 'base-image'
   self.assertTrue(
       helper.build_image_impl(helper.Project(image_name), pull=True))
   mock_pull_images.assert_called_with()