Ejemplo n.º 1
0
def set_sanitizer_options(fuzzer_path):
  """Sets sanitizer options based on .options file overrides and what this
  script requires."""
  engine_common.process_sanitizer_options_overrides(fuzzer_path)
  sanitizer_options_var = environment.get_current_memory_tool_var()
  sanitizer_options = environment.get_memory_tool_options(
      sanitizer_options_var, {})
  sanitizer_options['exitcode'] = constants.TARGET_ERROR_EXITCODE
  environment.set_memory_tool_options(sanitizer_options_var, sanitizer_options)
Ejemplo n.º 2
0
    def run(self, input_directory, output_directory, no_of_files):
        """Run the fuzzer to generate testcases."""

        fuzzer_binary_name, fuzzer_path = self._get_fuzzer_binary_name_and_path(
        )

        project_qualified_name = data_types.fuzz_target_project_qualified_name(
            utils.current_project(), fuzzer_binary_name)

        arguments = self.generate_arguments(fuzzer_path)
        corpus_directory = get_corpus_directory(input_directory,
                                                project_qualified_name)

        # Create fuzz testcases.
        for i in range(no_of_files):
            # Contents of testcase file don't matter at this point. Need to create
            # something non-null so that it is not ignored.
            testcase_file_path = os.path.join(
                output_directory, '%s%d' % (testcase_manager.FUZZ_PREFIX, i))
            utils.write_data_to_file(' ', testcase_file_path)

            # Write the flags file containing command line for running launcher
            # script.
            flags_file_path = os.path.join(
                output_directory, '%s%d' % (testcase_manager.FLAGS_PREFIX, i))
            flags = ['%TESTCASE%', fuzzer_binary_name]
            if arguments:
                flags.append(arguments)

            flags_file_content = ' '.join(flags)
            utils.write_data_to_file(flags_file_content, flags_file_path)

        output = 'Generated %d testcase for fuzzer %s.\n' % (
            no_of_files, fuzzer_binary_name)
        output += 'metadata::fuzzer_binary_name: %s\n' % fuzzer_binary_name

        issue_owners = engine_common.get_issue_owners(fuzzer_path)
        if issue_owners:
            output += 'metadata::issue_owners: %s\n' % ','.join(issue_owners)

        issue_labels = engine_common.get_issue_labels(fuzzer_path)
        if issue_labels:
            output += 'metadata::issue_labels: %s\n' % ','.join(issue_labels)

        issue_components = engine_common.get_issue_components(fuzzer_path)
        if issue_components:
            output += 'metadata::issue_components: %s\n' % ','.join(
                issue_components)

        # Update *SAN_OPTIONS in current environment from .options file. This
        # environment is used in fuzz task later for deriving the environment
        # string in |get_environment_settings_as_string| and embedding this as
        # part of stacktrace.
        engine_common.process_sanitizer_options_overrides(fuzzer_path)

        return BuiltinFuzzerResult(output=output,
                                   corpus_directory=corpus_directory)
Ejemplo n.º 3
0
 def test_sanitizer_options_changed(self, options_name, section_name):
   """Test that sanitizer options set in .options file are added to the
   environment variable."""
   environment.set_value(options_name, 'a=1:b=2:c=1')
   self.fs.create_file(
       self.fuzz_target_options_file,
       contents='[{section_name}]\nc=3:d=4'.format(section_name=section_name))
   engine_common.process_sanitizer_options_overrides(self.fuzz_target)
   self.assertEqual('a=1:b=2:c=3:d=4', environment.get_value(options_name))
Ejemplo n.º 4
0
 def test_sanitizer_options_not_changed_unrelated_section(
         self, options_name, section_name):
     """Test that sanitizer options are not changed when provided an unrelated
 sanitizer section name."""
     environment.set_value(options_name, 'a=1:b=2:c=1')
     self.fs.create_file(self.fuzz_target_options_file,
                         contents='[{section_name}]\nc=3:d=4'.format(
                             section_name=section_name))
     engine_common.process_sanitizer_options_overrides(self.fuzz_target)
     self.assertEqual('a=1:b=2:c=1', environment.get_value(options_name))
Ejemplo n.º 5
0
 def test_options_file(self):
     """Test *SAN_OPTIONS set from .options file."""
     os.environ['ASAN_OPTIONS'] = self.DUMMY_OPTION
     os.environ['MSAN_OPTIONS'] = self.DUMMY_OPTION
     self._create_file(
         self.TARGET_OPTIONS_PATH,
         contents='[asan]\nfake_option=1\n[msan]\nfake_option=2')
     engine_common.process_sanitizer_options_overrides(self.TARGET_PATH)
     launcher.set_additional_sanitizer_options_for_afl_fuzz()
     self.assert_sanitizer_opts_set('ASAN_OPTIONS', self.DUMMY_OPTION,
                                    'fake_option=1')
     self.assert_sanitizer_opts_set('MSAN_OPTIONS', self.DUMMY_OPTION,
                                    'fake_option=2')
Ejemplo n.º 6
0
    def run(self, input_directory, output_directory, no_of_files):
        """Run the fuzzer to generate testcases."""
        build_directory = environment.get_value('BUILD_DIR')

        if not build_directory:
            raise BuiltinFuzzerException(
                'BUILD_DIR environment variable is not set.')

        fuzzers = fuzzers_utils.get_fuzz_targets(build_directory)

        if not fuzzers:
            raise BuiltinFuzzerException(
                'No fuzzer binaries found in |BUILD_DIR| directory.')

        fuzzer_binary_name = environment.get_value('FUZZ_TARGET')
        if fuzzer_binary_name:
            fuzzer_path = _get_fuzzer_path(fuzzers, fuzzer_binary_name)
        else:
            fuzzer_path = random.SystemRandom().choice(fuzzers)
            fuzzer_binary_name = os.path.basename(fuzzer_path)

        project_qualified_name = data_types.fuzz_target_project_qualified_name(
            utils.current_project(), fuzzer_binary_name)

        corpus_directory = os.path.join(input_directory,
                                        project_qualified_name)
        if environment.is_trusted_host():
            from bot.untrusted_runner import file_host
            corpus_directory = file_host.rebase_to_worker_root(
                corpus_directory)

        arguments = self.generate_arguments(fuzzer_path)

        # Create corpus directory if it does not exist already.
        if environment.is_trusted_host():
            from bot.untrusted_runner import file_host
            file_host.create_directory(corpus_directory,
                                       create_intermediates=True)
        else:
            if not os.path.exists(corpus_directory):
                os.mkdir(corpus_directory)

        # Create fuzz testcases.
        for i in range(no_of_files):
            # Contents of testcase file don't matter at this point. Need to create
            # something non-null so that it is not ignored.
            testcase_file_path = os.path.join(output_directory,
                                              '%s%d' % (tests.FUZZ_PREFIX, i))
            utils.write_data_to_file(' ', testcase_file_path)

            # Write the flags file containing command line for running launcher
            # script.
            flags_file_path = os.path.join(output_directory,
                                           '%s%d' % (tests.FLAGS_PREFIX, i))
            flags = ['%TESTCASE%', fuzzer_binary_name]
            if arguments:
                flags.append(arguments)

            flags_file_content = ' '.join(flags)
            utils.write_data_to_file(flags_file_content, flags_file_path)

        output = 'Generated %d testcase for fuzzer %s.\n' % (
            no_of_files, fuzzer_binary_name)
        output += 'metadata::fuzzer_binary_name: %s\n' % fuzzer_binary_name

        issue_owners = engine_common.get_issue_owners(fuzzer_path)
        if issue_owners:
            output += 'metadata::issue_owners: %s\n' % ','.join(issue_owners)

        issue_labels = engine_common.get_issue_labels(fuzzer_path)
        if issue_labels:
            output += 'metadata::issue_labels: %s\n' % ','.join(issue_labels)

        # Update *SAN_OPTIONS in current environment from .options file. This
        # environment is used in fuzz task later for deriving the environment
        # string in |get_environment_settings_as_string| and embedding this as
        # part of stacktrace.
        engine_common.process_sanitizer_options_overrides(fuzzer_path)

        return BuiltinFuzzerResult(output=output,
                                   corpus_directory=corpus_directory)
Ejemplo n.º 7
0
 def test_sanitizer_options_not_changed_no_options_file(self, options_name):
     """Test that sanitizer options are not changed and no exception occurs
 when .options file is not provided."""
     environment.set_value(options_name, 'a=1:b=2:c=1')
     engine_common.process_sanitizer_options_overrides(self.fuzz_target)
     self.assertEqual('a=1:b=2:c=1', environment.get_value(options_name))
Ejemplo n.º 8
0
def main(argv):
    """Run afl as specified by argv."""
    atexit.register(fuzzer_utils.cleanup)

    # Initialize variables.
    _, testcase_file_path, target_name = argv[:3]
    input_directory = environment.get_value('FUZZ_CORPUS_DIR')
    fuzzer_name = data_types.fuzz_target_project_qualified_name(
        utils.current_project(), target_name)

    # Initialize log handler.
    logs.configure(
        'run_fuzzer', {
            'fuzzer': fuzzer_name,
            'engine': 'afl',
            'job_name': environment.get_value('JOB_NAME')
        })

    build_directory = environment.get_value('BUILD_DIR')
    fuzzer_path = engine_common.find_fuzzer_path(build_directory, target_name)
    if not fuzzer_path:
        # This is an expected case when doing regression testing with old builds
        # that do not have that fuzz target. It can also happen when a host sends a
        # message to an untrusted worker that just restarted and lost information on
        # build directory.
        logs.log_warn('Could not find fuzz target %s.' % target_name)
        return

    # Install signal handler.
    signal.signal(signal.SIGTERM, engine_common.signal_term_handler)

    # Set up temp dir.
    engine_common.recreate_directory(fuzzer_utils.get_temp_dir())

    config = AflConfig.from_target_path(fuzzer_path)

    runner = AflRunner(fuzzer_path, config, testcase_file_path,
                       input_directory)

    # Add *SAN_OPTIONS overrides from .options file.
    engine_common.process_sanitizer_options_overrides(fuzzer_path)

    # If we don't have a corpus, then that means this is not a fuzzing run.
    if not input_directory:
        load_testcase_if_exists(runner, testcase_file_path)
        return

    # Make sure afl won't exit because of bad sanitizer options.
    set_additional_sanitizer_options_for_afl_fuzz()

    # Execute afl-fuzz on the fuzzing target.
    fuzz_result = runner.fuzz()

    # Print info for the fuzzer logs.
    command = fuzz_result.command
    print('Command: {0}\n'
          'Bot: {1}\n'
          'Time ran: {2}\n').format(engine_common.get_command_quoted(command),
                                    BOT_NAME, fuzz_result.time_executed)

    print fuzz_result.output
    runner.strategies.print_strategies()

    if fuzz_result.return_code:
        # If AFL returned a non-zero return code quit now without getting stats,
        # since they would be meaningless.
        print runner.fuzzer_stderr
        return

    stats_getter = stats.StatsGetter(runner.afl_output.stats_path,
                                     config.dict_path)
    try:
        new_units_generated, new_units_added, corpus_size = (
            runner.libfuzzerize_corpus())
        stats_getter.set_stats(fuzz_result.time_executed, new_units_generated,
                               new_units_added, corpus_size, runner.strategies,
                               runner.fuzzer_stderr, fuzz_result.output)

        engine_common.dump_big_query_data(stats_getter.stats,
                                          testcase_file_path, AFL_PREFIX,
                                          fuzzer_name, command)

    finally:
        print runner.fuzzer_stderr

    # Whenever new units are added to corpus, record the stats to make them
    # easily searchable in stackdriver.
    if new_units_added:
        logs.log('New units added to corpus: %d.' % new_units_added,
                 stats=stats_getter.stats)