def test_test_for_reproducibility_greybox_succeed_after_multiple_tries(
            self):
        """Test test_for_reproducibility with with failure on first run and then
    succeed on remaining runs  (greybox)."""
        mock_engine = mock.Mock()
        mock_engine.reproduce.side_effect = [
            engine.ReproduceResult(['cmd'], 0, 0, 'output'),
            engine.ReproduceResult(['cmd'], 1, 1, 'crash'),
            engine.ReproduceResult(['cmd'], 1, 1, 'crash'),
        ]
        self.mock.get.return_value = mock_engine

        result = testcase_manager.test_for_reproducibility(
            'engine',
            'engine_target',
            '/fuzz-testcase',
            'state',
            expected_security_flag=False,
            test_timeout=10,
            http_flag=False,
            gestures=None)
        self.assertTrue(result)

        self.assertEqual(3, mock_engine.reproduce.call_count)
        self.mock.log.assert_has_calls([
            mock.call('No crash occurred (round 1).',
                      output=self.GREYBOX_FUZZER_NO_CRASH),
            mock.call('Crash occurred in 1 seconds (round 2). State:\nstate',
                      output=self.GREYBOX_FUZZER_CRASH),
            mock.call('Crash occurred in 1 seconds (round 3). State:\nstate',
                      output=self.GREYBOX_FUZZER_CRASH),
            mock.call('Crash is reproducible.'),
        ])
    def test_test_for_crash_with_retries_greybox_succeed_no_comparison(self):
        """Test test_for_crash_with_retries reproducing a crash with compare_crash
    set to False (greybox)."""
        mock_engine = mock.Mock()
        mock_engine.reproduce.side_effect = [
            engine.ReproduceResult(['cmd'], 0, 0, 'output'),
            engine.ReproduceResult(['cmd'], 1, 1, 'crash'),
        ]
        self.mock.get.return_value = mock_engine

        crash_result = testcase_manager.test_for_crash_with_retries(
            self.greybox_testcase, '/fuzz-testcase', 10, compare_crash=False)
        self.assertEqual(1, crash_result.return_code)
        self.assertEqual(1, crash_result.crash_time)
        self.assertEqual(self.GREYBOX_FUZZER_CRASH, crash_result.output)
        self.assertEqual(2, mock_engine.reproduce.call_count)
        mock_engine.reproduce.assert_has_calls([
            mock.call('/build_dir/target', '/fuzz-testcase',
                      ['-arg1', '-arg2'], 120),
            mock.call('/build_dir/target', '/fuzz-testcase',
                      ['-arg1', '-arg2'], 10),
        ])
        self.mock.log.assert_has_calls([
            mock.call('No crash occurred (round 1).',
                      output=self.GREYBOX_FUZZER_NO_CRASH),
            mock.call('Crash occurred in 1 seconds (round 2). State:\nstate',
                      output=self.GREYBOX_FUZZER_CRASH),
            mock.call('Crash stacktrace comparison skipped.')
        ])
    def test_test_for_reproducibility_greybox_succeed(self):
        """Test test_for_reproducibility with success on all runs (greybox)."""
        mock_engine = mock.Mock()
        mock_engine.reproduce.return_value = engine.ReproduceResult(['cmd'], 1,
                                                                    1, 'crash')
        self.mock.get.return_value = mock_engine

        result = testcase_manager.test_for_reproducibility(
            'engine',
            'engine_target',
            '/fuzz-testcase',
            'state',
            expected_security_flag=False,
            test_timeout=10,
            http_flag=False,
            gestures=None)
        self.assertTrue(result)

        # Only 2/3 runs needed to verify reproducibility.
        self.assertEqual(2, mock_engine.reproduce.call_count)
        self.mock.log.assert_has_calls([
            mock.call('Crash occurred in 1 seconds (round 1). State:\nstate',
                      output=self.GREYBOX_FUZZER_CRASH),
            mock.call('Crash occurred in 1 seconds (round 2). State:\nstate',
                      output=self.GREYBOX_FUZZER_CRASH),
            mock.call('Crash is reproducible.'),
        ])
    def test_test_for_crash_with_retries_greybox_fail(self):
        """Test test_for_crash_with_retries failing to reproduce a crash
    (greybox)."""
        mock_engine = mock.Mock()
        mock_engine.reproduce.return_value = engine.ReproduceResult(['cmd'], 0,
                                                                    0,
                                                                    'output')
        self.mock.get.return_value = mock_engine

        crash_result = testcase_manager.test_for_crash_with_retries(
            self.greybox_testcase, '/fuzz-testcase', 10)
        self.assertEqual(0, crash_result.return_code)
        self.assertEqual(0, crash_result.crash_time)
        self.assertEqual(self.GREYBOX_FUZZER_NO_CRASH, crash_result.output)
        self.assertEqual(3, mock_engine.reproduce.call_count)
        mock_engine.reproduce.assert_has_calls([
            mock.call('/build_dir/target', '/fuzz-testcase',
                      ['-arg1', '-arg2'], 120),
            mock.call('/build_dir/target', '/fuzz-testcase',
                      ['-arg1', '-arg2'], 10),
            mock.call('/build_dir/target', '/fuzz-testcase',
                      ['-arg1', '-arg2'], 10),
        ])
        self.mock.log.assert_has_calls([
            mock.call('No crash occurred (round 1).',
                      output=self.GREYBOX_FUZZER_NO_CRASH),
            mock.call('No crash occurred (round 2).',
                      output=self.GREYBOX_FUZZER_NO_CRASH),
            mock.call('No crash occurred (round 3).',
                      output=self.GREYBOX_FUZZER_NO_CRASH),
            mock.call("Didn't crash at all.")
        ])
Esempio n. 5
0
  def cleanse(self, target_path, arguments, input_path, output_path, max_time):
    """Optional (but recommended): Cleanse a testcase.

    Args:
      target_path: Path to the target.
      arguments: Additional arguments needed for testcase cleanse.
      input_path: Path to the reproducer input.
      output_path: Path to the cleansed output.
      max_time: Maximum allowed time for the cleanse.

    Returns:
      A ReproduceResult.

    Raises:
      TimeoutError: If the cleanse exceeds max_time.
    """
    runner = libfuzzer.get_runner(target_path)
    libfuzzer.set_sanitizer_options(target_path)

    cleanse_tmp_dir = self._create_temp_corpus_dir('cleanse-workdir')
    result = runner.cleanse_crash(
        input_path,
        output_path,
        max_time,
        artifact_prefix=cleanse_tmp_dir,
        additional_args=arguments)

    if result.timed_out:
      raise TimeoutError('Cleanse timed out\n' + result.output)

    return engine.ReproduceResult(result.command, result.return_code,
                                  result.time_executed, result.output)
Esempio n. 6
0
    def reproduce(self, target_path, input_path, arguments, max_time):  # pylint: disable=unused-argument
        """Reproduce a crash given an input.
       Example: ./syz-crush -config my.cfg -infinite=false -restart_time=20s
        crash-qemu-1-1455745459265726910

    Args:
      target_path: Path to the target.
      input_path: Path to the reproducer input.
      arguments: Additional arguments needed for reproduction.
      max_time: Maximum allowed time for the reproduction.

    Returns:
      A ReproduceResult.
    """
        binary_dir = self.prepare_binary_path()
        syzkaller_runner = runner.get_runner(
            os.path.join(binary_dir, constants.SYZ_REPRO))
        repro_args = runner.get_config()
        repro_args.extend([
            '-infinite=false', '-restart_time={}s'.format(REPRO_TIME),
            input_path
        ])
        result = syzkaller_runner.repro(max_time, repro_args=repro_args)

        return engine.ReproduceResult(result.command, result.return_code,
                                      result.time_executed, result.output)
Esempio n. 7
0
  def reproduce(self, target_path, input_path, arguments, max_time):
    """Reproduce a crash given an input.
    Args:
      target_path: Path to the fuzzer script or binary.
      input_path: Path to the reproducer input.
      arguments: Additional arguments needed for reproduction.
      max_time: Maximum allowed time for the reproduction.
    Returns:
      A ReproduceResult.
    """
    # For blackbox fuzzers, |target_path| supplies the path to the fuzzer script
    # rather than a target in the build archive.
    fuzzer_path = target_path
    os.chmod(fuzzer_path, 0o775)

    app_path = environment.get_value('APP_PATH')
    app_args = testcase_manager.get_command_line_for_application(
        get_arguments_only=True).strip()

    args = _get_arguments(app_path, app_args)
    args.append(f'--testcase_path={input_path}')

    result = _run_with_interpreter_if_needed(fuzzer_path, args, max_time)
    return engine.ReproduceResult(result.command, result.return_code,
                                  result.time_executed, result.output)
Esempio n. 8
0
  def reproduce(self, target_path, input_path, arguments, max_time):
    """Reproduce a crash given an input.

    Args:
      target_path: Path to the target.
      input_path: Path to the reproducer input.
      arguments: Additional arguments needed for reproduction.
      max_time: Maximum allowed time for the reproduction.

    Returns:
      A ReproduceResult.

    Raises:
      TimeoutError: If the reproduction exceeds max_time.
    """
    runner = libfuzzer.get_runner(target_path)
    libfuzzer.set_sanitizer_options(target_path)

    # Remove fuzzing specific arguments. This is only really needed for legacy
    # testcases, and can be removed in the distant future.
    arguments = arguments[:]
    libfuzzer.remove_fuzzing_arguments(arguments)

    runs_argument = constants.RUNS_FLAG + str(constants.RUNS_TO_REPRODUCE)
    arguments.append(runs_argument)

    result = runner.run_single_testcase(
        input_path, timeout=max_time, additional_args=arguments)

    if result.timed_out:
      raise TimeoutError('Reproducing timed out\n' + result.output)

    return engine.ReproduceResult(result.command, result.return_code,
                                  result.time_executed, result.output)
Esempio n. 9
0
    def reproduce(self, target_path, input_path, arguments, max_time):
        """Reproduce a crash given an input.

    Args:
      target_path: Path to the target.
      input_path: Path to the reproducer input.
      arguments: Additional arguments needed for reproduction.
      max_time: Maximum allowed time for the reproduction.

    Returns:
      A ReproduceResult.
    """
        config = launcher.AflConfig.from_target_path(target_path)
        input_directory = None  # Not required for reproduction.
        runner = launcher.prepare_runner(target_path, config, input_path,
                                         input_directory)

        reproduce_result = _run_single_testcase(runner, input_path)

        command = reproduce_result.command
        return_code = reproduce_result.return_code
        time_executed = reproduce_result.time_executed
        output = runner.fuzzer_stderr

        return engine.ReproduceResult(command, return_code, time_executed,
                                      output)
Esempio n. 10
0
def process_testcase(engine_name, tool_name, target_name, arguments,
                     testcase_path, output_path, timeout):
    """Process testcase on untrusted worker."""
    if tool_name == 'minimize':
        operation = untrusted_runner_pb2.ProcessTestcaseRequest.MINIMIZE
    else:
        operation = untrusted_runner_pb2.ProcessTestcaseRequest.CLEANSE

    rebased_testcase_path = file_host.rebase_to_worker_root(testcase_path)
    file_host.copy_file_to_worker(testcase_path, rebased_testcase_path)

    request = untrusted_runner_pb2.ProcessTestcaseRequest(
        engine=engine_name,
        operation=operation,
        target_name=target_name,
        arguments=arguments,
        testcase_path=file_host.rebase_to_worker_root(testcase_path),
        output_path=file_host.rebase_to_worker_root(output_path),
        timeout=timeout)

    response = host.stub().ProcessTestcase(request)

    rebased_output_path = file_host.rebase_to_worker_root(output_path)
    file_host.copy_file_from_worker(rebased_output_path, output_path)

    return engine.ReproduceResult(list(response.command), response.return_code,
                                  response.time_executed, response.output)
Esempio n. 11
0
    def repro(self, repro_timeout, repro_args):
        """This is where crash repro'ing is done.
    Args:
      repro_timeout: The maximum time in seconds that repro job is allowed
          to run for.
      repro_args: A sequence of arguments to be passed to the executable.
    """
        logs.log('Running Syzkaller testcase.')
        additional_args = copy.copy(repro_args)
        result = self.run_and_wait(additional_args, timeout=repro_timeout)
        result.return_code = self._crash_was_reproducible(result.output)

        if result.return_code:
            logs.log('Successfully reproduced crash.')
        else:
            logs.log('Failed to reproduce crash.')
        logs.log('Syzkaller repro testcase stopped.')
        return engine.ReproduceResult(result.command, result.return_code,
                                      result.time_executed, result.output)
Esempio n. 12
0
  def reproduce(self, target_path, input_path, arguments, max_time):  # pylint: disable=unused-argument
    """Reproduce a crash given an input.

    Args:
      target_path: Path to the target.
      input_path: Path to the reproducer input.
      arguments: Additional arguments needed for reproduction.
      max_time: Maximum allowed time for the reproduction.

    Returns:
      A ReproduceResult.
    """
    os.chmod(target_path, 0o775)
    runner = new_process.UnicodeProcessRunner(target_path)
    with open(input_path) as f:
      result = runner.run_and_wait(timeout=max_time, stdin=f)

    return engine.ReproduceResult(result.command, result.return_code,
                                  result.time_executed, result.output)
    def test_test_for_crash_with_retries_greybox_legacy(self):
        """Test test_for_crash_with_retries reproducing a legacy crash (greybox)."""
        mock_engine = mock.Mock()
        mock_engine.reproduce.side_effect = [
            engine.ReproduceResult(['cmd'], 1, 1, 'crash'),
        ]
        self.mock.get.return_value = mock_engine

        with open('/flags-testcase', 'w') as f:
            f.write('%TESTCASE% target -arg1 -arg2')

        testcase_manager.test_for_crash_with_retries(self.greybox_testcase,
                                                     '/fuzz-testcase', 10)
        mock_engine.reproduce.assert_has_calls([
            mock.call('/build_dir/target', '/fuzz-testcase',
                      ['-arg1', '-arg2'], 120),
        ])
        self.mock.log.assert_has_calls([
            mock.call('Crash occurred in 1 seconds (round 1). State:\nstate',
                      output=self.GREYBOX_FUZZER_CRASH),
            mock.call('Crash stacktrace is similar to original stacktrace.')
        ])
Esempio n. 14
0
def engine_reproduce(engine_impl, target_name, testcase_path, arguments,
                     timeout):
    """Run engine reproduce on untrusted worker."""
    rebased_testcase_path = file_host.rebase_to_worker_root(testcase_path)
    file_host.copy_file_to_worker(testcase_path, rebased_testcase_path)

    request = untrusted_runner_pb2.EngineReproduceRequest(
        engine=engine_impl.name,
        target_name=target_name,
        testcase_path=rebased_testcase_path,
        arguments=arguments,
        timeout=timeout)

    try:
        response = host.stub().EngineReproduce(request)
    except grpc.RpcError as e:
        if 'TargetNotFoundError' in repr(e):
            # Resurface the right exception.
            raise testcase_manager.TargetNotFoundError(
                'Failed to find target ' + target_name)
        raise

    return engine.ReproduceResult(list(response.command), response.return_code,
                                  response.time_executed, response.output)