Example #1
0
def do_bisect(bisect_type, source_id, project_name, engine, sanitizer,
              architecture, fuzz_target, old_commit, new_commit, testcase):
  """Do the actual bisect."""
  import bisector
  import build_specified_commit

  with tempfile.NamedTemporaryFile() as f:
    f.write(testcase)
    f.flush()

    build_data = build_specified_commit.BuildData(
        project_name=project_name,
        engine=engine,
        sanitizer=sanitizer,
        architecture=architecture)
    try:
      result = bisector.bisect(bisect_type, old_commit, new_commit, f.name,
                               fuzz_target, build_data)
    except bisector.BisectError as e:
      logging.error('Bisect failed with exception:\n%s', traceback.format_exc())
      return bisector.Result(e.repo_url, None)
    except Exception:
      logging.error('Bisect failed with unexpected exception:\n%s',
                    traceback.format_exc())
      return None

    if result.commit == old_commit:
      logging.error('Bisect failed for testcase %s, bisected to old_commit',
                    source_id)
      result = None

    return result
Example #2
0
    def test_build_fuzzers_from_commit(self):
        """Tests if the fuzzers can build at a proper 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.
    """
        test_data = os.path.join(TEST_DIR_PATH, 'testcases', 'yara_test_data')

        with tempfile.TemporaryDirectory() as tmp_dir:
            project_name = 'yara'
            old_commit = 'f79be4f2330f4b89ea2f42e1c44ca998c59a0c0f'
            new_commit = 'f50a39051ea8c7f10d6d8db9656658b49601caef'
            fuzzer = 'rules_fuzzer'

            yara_repo_manager = repo_manager.RepoManager(
                'https://github.com/VirusTotal/yara.git',
                tmp_dir,
                repo_name='yara')
            build_data = build_specified_commit.BuildData()
            build_data.sanitizer = 'address'
            build_data.architecture = 'x86_64'
            build_data.engine = 'libfuzzer'
            build_data.project_name = 'yara'
            build_specified_commit.build_fuzzers_from_commit(
                old_commit, yara_repo_manager, build_data)
            old_error_code = helper.reproduce_impl(project_name, fuzzer, False,
                                                   [], [], test_data)
            build_specified_commit.build_fuzzers_from_commit(
                new_commit, yara_repo_manager, build_data)
            new_error_code = helper.reproduce_impl(project_name, fuzzer, False,
                                                   [], [], test_data)
            self.assertNotEqual(new_error_code, old_error_code)
Example #3
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)
Example #4
0
def main():
    """Finds the commit SHA where an error was initally introduced."""
    logging.getLogger().setLevel(logging.INFO)
    utils.chdir_to_root()
    parser = argparse.ArgumentParser(
        description='git bisection for finding introduction of bugs')

    parser.add_argument('--project_name',
                        help='The name of the project where the bug occurred.',
                        required=True)
    parser.add_argument('--new_commit',
                        help='The newest commit SHA to be bisected.',
                        required=True)
    parser.add_argument('--old_commit',
                        help='The oldest commit SHA to be bisected.',
                        required=True)
    parser.add_argument('--fuzz_target',
                        help='The name of the fuzzer to be built.',
                        required=True)
    parser.add_argument('--test_case_path',
                        help='The path to test case.',
                        required=True)
    parser.add_argument('--engine',
                        help='The default is "libfuzzer".',
                        default='libfuzzer')
    parser.add_argument('--sanitizer',
                        default='address',
                        help='The default is "address".')
    parser.add_argument('--type',
                        choices=['regressed', 'fixed'],
                        help='The bisection type.',
                        required=True)
    parser.add_argument('--architecture', default='x86_64')
    args = parser.parse_args()

    build_data = build_specified_commit.BuildData(
        project_name=args.project_name,
        engine=args.engine,
        sanitizer=args.sanitizer,
        architecture=args.architecture)

    result = bisect(args.type, args.old_commit, args.new_commit,
                    args.test_case_path, args.fuzz_target, build_data)
    if not result.commit:
        logging.error('No error was found in commit range %s:%s',
                      args.old_commit, args.new_commit)
        return 1
    if result.commit == args.old_commit:
        logging.error(
            'Bisection Error: Both the first and the last commits in'
            'the given range have the same behavior, bisection is not possible. '
        )
        return 1
    if args.type == 'regressed':
        print('Error was introduced at commit %s' % result.commit)
    elif args.type == 'fixed':
        print('Error was fixed at commit %s' % result.commit)
    return 0
Example #5
0
 def test_bisect_invalid_repo(self):
     """Test the bisection method on a project that does not exist."""
     test_repo = test_repos.INVALID_REPO
     build_data = build_specified_commit.BuildData(
         project_name=test_repo.project_name,
         engine='libfuzzer',
         sanitizer='address',
         architecture='x86_64')
     with self.assertRaises(ValueError):
         bisector.bisect(test_repo.old_commit, test_repo.new_commit,
                         test_repo.test_case_path, test_repo.fuzz_target,
                         build_data)
Example #6
0
def main():
    """Finds the commit SHA where an error was initally introduced."""
    oss_fuzz_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
    if os.getcwd() != oss_fuzz_dir:
        print('Changing directory to OSS-Fuzz home directory')
        os.chdir(oss_fuzz_dir)
    parser = argparse.ArgumentParser(
        description='git bisection for finding introduction of bugs')

    parser.add_argument('--project_name',
                        help='The name of the project where the bug occurred.',
                        required=True)
    parser.add_argument('--commit_new',
                        help='The newest commit SHA to be bisected.',
                        required=True)
    parser.add_argument('--commit_old',
                        help='The oldest commit SHA to be bisected.',
                        required=True)
    parser.add_argument('--fuzz_target',
                        help='The name of the fuzzer to be built.',
                        required=True)
    parser.add_argument('--testcase',
                        help='The path to test case.',
                        required=True)
    parser.add_argument('--engine',
                        help='The default is "libfuzzer".',
                        default='libfuzzer')
    parser.add_argument('--sanitizer',
                        default='address',
                        help='The default is "address".')
    parser.add_argument('--architecture', default='x86_64')
    args = parser.parse_args()

    build_data = build_specified_commit.BuildData(
        project_name=args.project_name,
        engine=args.engine,
        sanitizer=args.sanitizer,
        architecture=args.architecture)

    error_sha = bisect(args.commit_old, args.commit_new, args.testcase,
                       args.fuzz_target, build_data)
    if not error_sha:
        print('No error was found in commit range %s:%s' %
              (args.commit_old, args.commit_new))
        return 1
    if error_sha == args.commit_old:
        print(
            'Bisection Error: Both the first and the last commits in the given '
            + 'range have the same behavior, bisection is not possible. ')
        return 1
    print('Error was introduced at commit %s' % error_sha)
    return 0
Example #7
0
 def test_bisect_curl(self):
     """Test the bisect method on the curl project."""
     build_data = build_specified_commit.BuildData(project_name='curl',
                                                   engine='libfuzzer',
                                                   sanitizer='address',
                                                   architecture='x86_64')
     commit_new = 'dda418266c99ceab368d723facb52069cbb9c8d5'
     commit_old = 'df26f5f9c36e19cd503c0e462e9f72ad37b84c82'
     fuzz_target = 'curl_fuzzer_ftp'
     testcase = os.path.join(TEST_DIR_PATH, 'testcases', 'curl_test_data')
     error_sha = bisector.bisect(commit_old, commit_new, testcase,
                                 fuzz_target, build_data)
     self.assertEqual(error_sha, 'df26f5f9c36e19cd503c0e462e9f72ad37b84c82')
Example #8
0
 def test_bisect(self):
     """Test the bisect method on example projects."""
     for test_repo in test_repos.TEST_REPOS:
         build_data = build_specified_commit.BuildData(
             project_name=test_repo.project_name,
             engine='libfuzzer',
             sanitizer='address',
             architecture='x86_64')
         error_sha = bisector.bisect(test_repo.old_commit,
                                     test_repo.new_commit,
                                     test_repo.test_case_path,
                                     test_repo.fuzz_target, build_data)
         self.assertEqual(error_sha, test_repo.intro_commit)
Example #9
0
 def test_bisect_usrsctp(self):
     """Test the bisect method on the usrsctp."""
     build_data = build_specified_commit.BuildData(project_name='usrsctp',
                                                   engine='libfuzzer',
                                                   sanitizer='address',
                                                   architecture='x86_64')
     commit_old = '4886aaa49fb90e479226fcfc3241d74208908232'
     commit_new = 'c710749b1053978179a027973a3ea3bccf20ee5c'
     testcase = os.path.join(TEST_DIR_PATH, 'testcases',
                             'usrsctp_test_data')
     fuzz_target = 'fuzzer_connect'
     error_sha = bisector.bisect(commit_old, commit_new, testcase,
                                 fuzz_target, build_data)
     self.assertEqual(error_sha, '457d6ead58e82584d9dcb826f6739347f59ebd3a')
Example #10
0
    def test_bisect_usrsctp_single_error_exists(self):
        """Tests what happens with a single with an error."""
        build_data = build_specified_commit.BuildData(project_name='usrsctp',
                                                      engine='libfuzzer',
                                                      sanitizer='address',
                                                      architecture='x86_64')

        commit_old = 'c710749b1053978179a027973a3ea3bccf20ee5c'
        commit_new = 'c710749b1053978179a027973a3ea3bccf20ee5c'
        testcase = os.path.join(TEST_DIR_PATH, 'testcases',
                                'usrsctp_test_data')
        fuzz_target = 'fuzzer_connect'
        error_sha = bisector.bisect(commit_old, commit_new, testcase,
                                    fuzz_target, build_data)
        self.assertEqual(error_sha, 'c710749b1053978179a027973a3ea3bccf20ee5c')
Example #11
0
 def test_bisect_libarchive(self):
     """Test the bisect method on libarchive."""
     build_data = build_specified_commit.BuildData(
         project_name='libarchive',
         engine='libfuzzer',
         sanitizer='address',
         architecture='x86_64')
     commit_new = '458e49358f17ec58d65ab1c45cf299baaf3c98d1'
     commit_old = '5bd2a9b6658a3a6efa20bb9ad75bd39a44d71da6'
     fuzz_target = 'libarchive_fuzzer'
     testcase = os.path.join(TEST_DIR_PATH, 'testcases',
                             'libarchive_test_data')
     error_sha = bisector.bisect(commit_old, commit_new, testcase,
                                 fuzz_target, build_data)
     self.assertEqual(error_sha, '840266712006de5e737f8052db920dfea2be4260')
Example #12
0
 def test_bisect_invalid_repo(self):
     """Test the bisection method on a project that does not exist."""
     build_data = build_specified_commit.BuildData(
         project_name='not-a-real-repo',
         engine='libfuzzer',
         sanitizer='address',
         architecture='x86_64')
     commit_old = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
     commit_new = 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'
     testcase = os.path.join(TEST_DIR_PATH, 'testcases',
                             'usrsctp_test_data')
     fuzz_target = 'fuzzer_connect'
     with self.assertRaises(ValueError):
         bisector.bisect(commit_old, commit_new, testcase, fuzz_target,
                         build_data)
Example #13
0
    def test_bisect_usrsctp_single_no_error_exists(self):
        """Tests what happens with a single with an error."""
        build_data = build_specified_commit.BuildData(project_name='usrsctp',
                                                      engine='libfuzzer',
                                                      sanitizer='address',
                                                      architecture='x86_64')

        commit_old = '4886aaa49fb90e479226fcfc3241d74208908232'
        commit_new = '4886aaa49fb90e479226fcfc3241d74208908232'
        testcase = os.path.join(TEST_DIR_PATH, 'testcases',
                                'usrsctp_test_data')
        fuzz_target = 'fuzzer_connect'
        error_sha = bisector.bisect(commit_old, commit_new, testcase,
                                    fuzz_target, build_data)
        self.assertEqual(error_sha, '4886aaa49fb90e479226fcfc3241d74208908232')
Example #14
0
def build_fuzzers(args):
    """Builds all of the fuzzers for a specific OSS-Fuzz project.

  Returns:
    True on success False on failure.
  """

    # TODO: Fix return value bubble to actually handle errors.
    with tempfile.TemporaryDirectory() as tmp_dir:
        inferred_url, repo_name = build_specified_commit.detect_main_repo(
            args.project_name, repo_name=args.repo_name)
        build_repo_manager = repo_manager.RepoManager(inferred_url,
                                                      tmp_dir,
                                                      repo_name=repo_name)
        build_data = build_specified_commit.BuildData()
        build_data.project_name = args.project_name
        build_data.sanitizer = 'address'
        build_data.engine = 'libfuzzer'
        build_data.architecture = 'x86_64'
        return build_specified_commit.build_fuzzers_from_commit(
            args.commit_sha, build_repo_manager, build_data) == 0