def test_fuzz_from_subset(self): """Tests fuzzing from corpus subset.""" self.mock.generate_weighted_strategy_pool.return_value = set_strategy_pool( [strategy.CORPUS_SUBSET_STRATEGY]) self.mock.get_fuzz_timeout.return_value = get_fuzz_timeout(5.0) _, corpus_path = setup_testcase_and_corpus('empty', 'corpus_with_some_files') engine_impl = engine.LibFuzzerEngine() target_path = engine_common.find_fuzzer_path(ANDROID_DATA_DIR, 'test_fuzzer') dict_path = target_path + '.dict' options = engine_impl.prepare(corpus_path, target_path, ANDROID_DATA_DIR) results = engine_impl.fuzz(target_path, options, TEMP_DIR, 10) self.assertEqual([ self.adb_path, 'shell', self.hwasan_options, self.device_path(target_path), '-max_len=256', '-timeout=25', '-rss_limit_mb=2048', '-dict=' + self.device_path(dict_path), '-artifact_prefix=' + self.device_path(TEMP_DIR) + '/', '-max_total_time=5', '-print_final_stats=1', self.device_path(os.path.join(TEMP_DIR, 'temp-1337/new')), self.device_path(os.path.join(TEMP_DIR, 'temp-1337/subset')), ], results.command) self.assertTrue(android.adb.file_exists(self.device_path(dict_path))) self.assert_has_stats(results.stats)
def test_fuzz_from_subset(self): """Tests fuzzing from corpus subset.""" self.mock.generate_weighted_strategy_pool.return_value = set_strategy_pool( [strategy.CORPUS_SUBSET_STRATEGY]) self.mock.get_fuzz_timeout.return_value = get_fuzz_timeout(5.0) _, corpus_path = setup_testcase_and_corpus("empty", "corpus_with_some_files") engine_impl = engine.LibFuzzerEngine() target_path = engine_common.find_fuzzer_path(DATA_DIR, "test_fuzzer") dict_path = target_path + ".dict" options = engine_impl.prepare(corpus_path, target_path, DATA_DIR) results = engine_impl.fuzz(target_path, options, TEMP_DIR, 10) self.compare_arguments( os.path.join(DATA_DIR, "test_fuzzer"), [ "-max_len=256", "-timeout=25", "-rss_limit_mb=2560", "-dict=" + dict_path, "-artifact_prefix=" + TEMP_DIR + "/", "-max_total_time=5", "-print_final_stats=1", ], [ os.path.join(TEMP_DIR, "temp-1337/new"), os.path.join(TEMP_DIR, "temp-1337/subset"), ], results.command, ) self.assert_has_stats(results.stats)
def test_analyze_dict(self): """Tests recommended dictionary analysis.""" test_helpers.patch( self, [ "bot.fuzzers.dictionary_manager.DictionaryManager." "parse_recommended_dictionary_from_log_lines", "bot.fuzzers.dictionary_manager.DictionaryManager." "update_recommended_dictionary", ], ) self.mock.parse_recommended_dictionary_from_log_lines.return_value = {'"USELESS_0"', '"APPLE"', '"USELESS_1"', '"GINGER"', '"USELESS_2"', '"BEET"', '"USELESS_3"',} self.mock.get_fuzz_timeout.return_value = get_fuzz_timeout(5.0) _, corpus_path = setup_testcase_and_corpus("empty", "corpus_with_some_files") engine_impl = engine.LibFuzzerEngine() target_path = engine_common.find_fuzzer_path(DATA_DIR, "analyze_dict_fuzzer") options = engine_impl.prepare(corpus_path, target_path, DATA_DIR) engine_impl.fuzz(target_path, options, TEMP_DIR, 10) expected_recommended_dictionary = {'"APPLE"', '"GINGER"', '"BEET"'} self.assertIn( expected_recommended_dictionary, self.mock.update_recommended_dictionary.call_args[0], )
def _update_issue_metadata(testcase): """Update issue metadata.""" if environment.is_trusted_host(): # Not applicable. return if testcase.uploader_email: # Trust the uploader specified metadata. return fuzz_target = testcase.get_fuzz_target() if not fuzz_target: return build_dir = environment.get_value('BUILD_DIR') target_path = engine_common.find_fuzzer_path(build_dir, fuzz_target.binary) if not target_path: logs.log_error('Failed to find target path for ' + fuzz_target.binary) return metadata = engine_common.get_all_issue_metadata(target_path) for key, value in six.iteritems(metadata): old_value = testcase.get_metadata(key) if old_value != value: logs.log('Updating issue metadata for {} from {} to {}.'.format( key, old_value, value)) testcase.set_metadata(key, value)
def test_fuzz_no_crash(self): """Tests fuzzing (no crash).""" self.mock.generate_weighted_strategy_pool.return_value = set_strategy_pool( [strategy.VALUE_PROFILE_STRATEGY]) self.mock.get_fuzz_timeout.return_value = get_fuzz_timeout(5.0) _, corpus_path = setup_testcase_and_corpus('empty', 'corpus') engine_impl = engine.LibFuzzerEngine() target_path = engine_common.find_fuzzer_path(DATA_DIR, 'test_fuzzer') options = engine_impl.prepare(corpus_path, target_path, DATA_DIR) results = engine_impl.fuzz(target_path, options, TEMP_DIR, 10) self.assert_has_stats(results.stats) self.compare_arguments(os.path.join(DATA_DIR, 'test_fuzzer'), [ '-max_len=256', '-timeout=25', '-rss_limit_mb=2048', '-use_value_profile=1', '-artifact_prefix=' + TEMP_DIR + '/', '-max_total_time=5', '-print_final_stats=1' ], [ os.path.join(TEMP_DIR, 'temp-1337/new'), os.path.join(TEMP_DIR, 'corpus') ], results.command) self.assertEqual(0, len(results.crashes)) # New items should've been added to the corpus. self.assertNotEqual(0, len(os.listdir(corpus_path)))
def test_fuzz_from_subset(self): """Tests fuzzing from corpus subset.""" self.mock.generate_weighted_strategy_pool.return_value = set_strategy_pool( [strategy.CORPUS_SUBSET_STRATEGY]) self.mock.get_fuzz_timeout.return_value = get_fuzz_timeout(5.0) _, corpus_path = setup_testcase_and_corpus('empty', 'corpus_with_some_files') engine_impl = engine.LibFuzzerEngine() target_path = engine_common.find_fuzzer_path(DATA_DIR, 'test_fuzzer') dict_path = target_path + '.dict' options = engine_impl.prepare(corpus_path, target_path, DATA_DIR) results = engine_impl.fuzz(target_path, options, TEMP_DIR, 10) self.compare_arguments(os.path.join(DATA_DIR, 'test_fuzzer'), [ '-max_len=256', '-timeout=25', '-rss_limit_mb=2048', '-dict=' + dict_path, '-artifact_prefix=' + TEMP_DIR + '/', '-max_total_time=5', '-print_final_stats=1' ], [ os.path.join(TEMP_DIR, 'temp-1337/new'), os.path.join(TEMP_DIR, 'temp-1337/subset') ], results.command) self.assert_has_stats(results.stats)
def test_exit_failure_logged(self): """Test that we log when libFuzzer's exit code indicates it ran into an error.""" test_helpers.patch(self, [ 'metrics.logs.log_error', ]) def mocked_log_error(*args, **kwargs): # pylint: disable=unused-argument self.assertIn(engine.ENGINE_ERROR_MESSAGE, args[0]) self.mock.log_error.side_effect = mocked_log_error _, corpus_path = setup_testcase_and_corpus('empty', 'corpus_with_some_files') target_path = engine_common.find_fuzzer_path(DATA_DIR, 'exit_fuzzer') engine_impl = engine.LibFuzzerEngine() options = engine_impl.prepare(corpus_path, target_path, DATA_DIR) options.extra_env['EXIT_FUZZER_CODE'] = '1' results = engine_impl.fuzz(target_path, options, TEMP_DIR, 10) self.assertEqual(1, self.mock.log_error.call_count) self.assertEqual(1, len(results.crashes)) self.assertEqual(fuzzer_utils.get_temp_dir(), os.path.dirname(results.crashes[0].input_path)) self.assertEqual(0, os.path.getsize(results.crashes[0].input_path))
def test_fuzz_no_crash(self): """Test fuzzing (no crash).""" _, corpus_path = setup_testcase_and_corpus('empty', 'corpus') engine_impl = engine.HonggfuzzEngine() target_path = engine_common.find_fuzzer_path(DATA_DIR, 'test_fuzzer') options = engine_impl.prepare(corpus_path, target_path, DATA_DIR) results = engine_impl.fuzz(target_path, options, TEMP_DIR, 10) self.assertListEqual([ os.path.join(DATA_DIR, 'honggfuzz'), '-n', '1', '--exit_upon_crash', '-v', '-z', '-P', '-S', '--rlimit_rss', '2560', '--timeout', '25', '--dict', os.path.join(DATA_DIR, 'test_fuzzer.dict'), '--input', os.path.join(TEMP_DIR, 'corpus'), '--workspace', TEMP_DIR, '--run_time', '10', '--', target_path, ], results.command) self.assertGreater(len(os.listdir(corpus_path)), 0) self.assert_has_stats(results)
def test_fuzz_with_mutator_plugin(self): """Tests fuzzing with a mutator plugin.""" self.mock.get_fuzz_timeout.return_value = get_fuzz_timeout(5.0) os.environ["MUTATOR_PLUGINS_DIR"] = os.path.join(TEMP_DIR, "mutator-plugins") # TODO(metzman): Remove the old binary and switch the test to the new one. fuzz_target_name = "test_fuzzer_old" plugin_archive_name = "custom_mutator_plugin-libfuzzer_asan-test_fuzzer_old.zip" # Call before setting up the plugin since this call will erase the directory # the plugin is written to. _, corpus_path = setup_testcase_and_corpus("empty", "empty_corpus") plugin_archive_path = os.path.join(DATA_DIR, plugin_archive_name) self.mock.generate_weighted_strategy_pool.return_value = set_strategy_pool( [strategy.MUTATOR_PLUGIN_STRATEGY]) self.mock._get_mutator_plugins_from_bucket.return_value = [ # pylint: disable=protected-access plugin_archive_name ] self.mock._download_mutator_plugin_archive.return_value = ( # pylint: disable=protected-access plugin_archive_path) custom_mutator_print_string = "CUSTOM MUTATOR\n" try: target_path = engine_common.find_fuzzer_path(DATA_DIR, fuzz_target_name) engine_impl = engine.LibFuzzerEngine() options = engine_impl.prepare(corpus_path, target_path, DATA_DIR) results = engine_impl.fuzz(target_path, options, TEMP_DIR, 10) finally: shutil.rmtree(os.environ["MUTATOR_PLUGINS_DIR"]) # custom_mutator_print_string gets printed before the custom mutator mutates # a test case. Assert that the count is greater than 1 to ensure that the # function didn't crash on its first execution (after printing). self.assertGreater(results.logs.count(custom_mutator_print_string), 1)
def test_single_testcase_crash(self): """Tests libfuzzer with a crashing testcase.""" testcase_path, _ = setup_testcase_and_corpus("crash", "empty_corpus") engine_impl = engine.LibFuzzerEngine() target_path = engine_common.find_fuzzer_path(ANDROID_DATA_DIR, "test_fuzzer") result = engine_impl.reproduce(target_path, testcase_path, ["-timeout=60", "-rss_limit_mb=2560"], 65) self.assertEqual( [ self.adb_path, "shell", self.hwasan_options, self.device_path(target_path), "-timeout=60", "-rss_limit_mb=2560", "-runs=100", self.device_path(testcase_path), ], result.command, ) self.assertIn( "ERROR: HWAddressSanitizer: SEGV on unknown address 0x000000000000", result.output, )
def engine_reproduce(engine_impl, target_name, testcase_path, arguments, timeout): """Do engine reproduction.""" if environment.is_trusted_host(): from bot.untrusted_runner import tasks_host return tasks_host.engine_reproduce(engine_impl, target_name, testcase_path, arguments, timeout) build_dir = environment.get_value('BUILD_DIR') is_blackbox = engine_impl.name == 'blackbox' target_path = engine_common.find_fuzzer_path(build_dir, target_name, is_blackbox=is_blackbox) if not target_path: raise TargetNotFoundError('Failed to find target ' + target_name) result = engine_impl.reproduce(target_path, testcase_path, list(arguments), timeout) # This matches the check in process_handler.run_process. if not result.return_code and \ (crash_analyzer.is_memory_tool_crash(result.output) or crash_analyzer.is_check_failure_crash(result.output)): result.return_code = 1 return result
def __init__(self, fuzzer_name, testcase_path, test_timeout, gestures, needs_http=False): self._testcase_path = testcase_path self._test_timeout = test_timeout self._gestures = gestures self._needs_http = needs_http engine_impl = engine.get(fuzzer_name) if engine_impl: self._is_black_box = False self._engine_impl = engine_impl # Read target_name + args from flags file. additional_command_line_flags = get_additional_command_line_flags( testcase_path) self._arguments = additional_command_line_flags.split() target_name = self._arguments.pop(0) build_dir = environment.get_value('BUILD_DIR') self._target_path = engine_common.find_fuzzer_path( build_dir, target_name) if not self._target_path: raise TargetNotFoundError('Failed to find target ' + target_name) else: self._is_black_box = True self._command = get_command_line_for_application( testcase_path, needs_http=needs_http)
def __init__(self, build_directory, context): self.build_directory = build_directory self.context = context self.fuzzer_path = engine_common.find_fuzzer_path( self.build_directory, self.context.fuzz_target.binary) if not self.fuzzer_path: raise CorpusPruningException('Failed to get fuzzer path for %s.' % self.context.fuzz_target.binary) fuzz_inputs_disk = environment.get_value('FUZZ_INPUTS_DISK') self.runner = libfuzzer.get_runner(self.fuzzer_path, temp_dir=fuzz_inputs_disk) if context.use_minijail: self.runner.chroot.add_binding( minijail.ChrootBinding(self.context.initial_corpus_path, '/corpus', False)) self.runner.chroot.add_binding( minijail.ChrootBinding(self.context.minimized_corpus_path, '/min', True)) self.runner.chroot.add_binding( minijail.ChrootBinding(self.context.shared_corpus_path, '/shared', False)) self.runner.chroot.add_binding( minijail.ChrootBinding(self.context.bad_units_path, '/bad_units', True)) self.fuzzer_options = options.get_fuzz_target_options(self.fuzzer_path)
def test_merge_reductions(self): """Tests that reduced testcases are merged back into the original corpus without deleting the larger version.""" self.mock.get_fuzz_timeout.return_value = get_fuzz_timeout(1.0) _, corpus_path = setup_testcase_and_corpus('empty', 'empty_corpus') fuzz_target_name = 'analyze_dict_fuzzer' test_helpers.patch(self, [ 'bot.fuzzers.libFuzzer.engine.LibFuzzerEngine._create_merge_corpus_dir', 'system.shell.get_directory_file_count', ]) self.mock.get_directory_file_count.side_effect = ( mock_get_directory_file_count) minimal_unit_contents = 'APPLE' minimal_unit_hash = '569bea285d70dda2218f89ef5454ea69fb5111ef' nonminimal_unit_contents = 'APPLEO' nonminimal_unit_hash = '540d9ba6239483d60cd7448a3202b96c90409186' def mocked_create_merge_directory(_): """A mocked version of create_merge_directory that adds some interesting files to the merge corpus and initial corpus.""" merge_directory_path = launcher.create_corpus_directory( 'merge-corpus') shell.create_directory(merge_directory_path, create_intermediates=True, recreate=True) # Write the minimal unit to the merge directory. minimal_unit_path = os.path.join(merge_directory_path, minimal_unit_hash) with open(minimal_unit_path, 'w+') as file_handle: file_handle.write(minimal_unit_contents) # Write the nonminimal unit to the corpus directory. nonminimal_unit_path = os.path.join(corpus_path, nonminimal_unit_hash) with open(nonminimal_unit_path, 'w+') as file_handle: file_handle.write(nonminimal_unit_contents) return merge_directory_path # pylint: disable=protected-access self.mock._create_merge_corpus_dir.side_effect = ( mocked_create_merge_directory) target_path = engine_common.find_fuzzer_path(DATA_DIR, fuzz_target_name) engine_impl = engine.LibFuzzerEngine() options = engine_impl.prepare(corpus_path, target_path, DATA_DIR) options.arguments.append('-runs=10') engine_impl.fuzz(target_path, options, TEMP_DIR, 10) # Verify that both the newly found minimal testcase and the nonminimal # testcase are in the corpus. self.assertIn(minimal_unit_hash, os.listdir(corpus_path)) self.assertIn(nonminimal_unit_hash, os.listdir(corpus_path))
def test_reproduce(self): """Tests reproducing a crash.""" testcase_path, _ = setup_testcase_and_corpus('crash', 'empty_corpus') engine_impl = engine.HonggfuzzEngine() target_path = engine_common.find_fuzzer_path(DATA_DIR, 'test_fuzzer') result = engine_impl.reproduce(target_path, testcase_path, [], 65) self.assertListEqual([target_path], result.command) self.assertIn('ERROR: AddressSanitizer: heap-use-after-free', result.output)
def test_single_testcase_crash(self): """Tests launcher with a crashing testcase.""" testcase_path, _ = setup_testcase_and_corpus('crash', 'empty_corpus') engine_impl = engine.LibFuzzerEngine() target_path = engine_common.find_fuzzer_path(DATA_DIR, 'test_fuzzer') result = engine_impl.reproduce(target_path, testcase_path, [], 30) self.assertIn( 'ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000', result.output)
def test_merge_reductions(self): """Tests that reduced testcases are merged back into the original corpus without deleting the larger version.""" self.mock.get_fuzz_timeout.return_value = get_fuzz_timeout(1.0) _, corpus_path = setup_testcase_and_corpus("empty", "empty_corpus") fuzz_target_name = "analyze_dict_fuzzer" test_helpers.patch( self, [ "bot.fuzzers.libFuzzer.engine.LibFuzzerEngine._create_merge_corpus_dir", "system.shell.get_directory_file_count", ], ) self.mock.get_directory_file_count.side_effect = mock_get_directory_file_count minimal_unit_contents = "APPLE" minimal_unit_hash = "569bea285d70dda2218f89ef5454ea69fb5111ef" nonminimal_unit_contents = "APPLEO" nonminimal_unit_hash = "07aef0e305db0779f3b52ab4dad975a1b737c461" def mocked_create_merge_directory(_): """A mocked version of create_merge_directory that adds some interesting files to the merge corpus and initial corpus.""" merge_directory_path = libfuzzer.create_corpus_directory("merge-corpus") # Write the minimal unit to the new corpus directory. new_corpus_directory_path = libfuzzer.create_corpus_directory("new") minimal_unit_path = os.path.join(new_corpus_directory_path, minimal_unit_hash) with open(minimal_unit_path, "w+") as file_handle: file_handle.write(minimal_unit_contents) # Write the nonminimal unit to the corpus directory. nonminimal_unit_path = os.path.join(corpus_path, nonminimal_unit_hash) with open(nonminimal_unit_path, "w+") as file_handle: file_handle.write(nonminimal_unit_contents) return merge_directory_path # pylint: disable=protected-access self.mock._create_merge_corpus_dir.side_effect = mocked_create_merge_directory target_path = engine_common.find_fuzzer_path(DATA_DIR, fuzz_target_name) engine_impl = engine.LibFuzzerEngine() options = engine_impl.prepare(corpus_path, target_path, DATA_DIR) options.arguments.append("-runs=10") engine_impl.fuzz(target_path, options, TEMP_DIR, 10) # Verify that both the newly found minimal testcase and the nonminimal # testcase are in the corpus. self.assertIn(minimal_unit_hash, os.listdir(corpus_path)) self.assertIn(nonminimal_unit_hash, os.listdir(corpus_path))
def __init__(self, build_directory, context): self.build_directory = build_directory self.context = context self.target_path = engine_common.find_fuzzer_path( self.build_directory, self.context.fuzz_target.binary) if not self.target_path: raise CorpusPruningException("Failed to get fuzzer path for %s." % self.context.fuzz_target.binary) self.fuzzer_options = options.get_fuzz_target_options(self.target_path)
def engine_reproduce(engine_impl, target_name, testcase_path, arguments, timeout): """Do engine reproduction.""" if environment.is_trusted_host(): from bot.untrusted_runner import tasks_host return tasks_host.engine_reproduce(engine_impl, target_name, testcase_path, arguments, timeout) build_dir = environment.get_value('BUILD_DIR') target_path = engine_common.find_fuzzer_path(build_dir, target_name) if not target_path: raise TargetNotFoundError('Failed to find target ' + target_name) return engine_impl.reproduce(target_path, testcase_path, list(arguments), timeout)
def test_single_testcase_crash(self): """Tests libfuzzer with a crashing testcase.""" testcase_path, _ = setup_testcase_and_corpus('crash', 'empty_corpus') engine_impl = engine.LibFuzzerEngine() target_path = engine_common.find_fuzzer_path(DATA_DIR, 'test_fuzzer') result = engine_impl.reproduce(target_path, testcase_path, ['-timeout=60', '-rss_limit_mb=2560'], 65) self.compare_arguments( os.path.join(DATA_DIR, 'test_fuzzer'), ['-timeout=60', '-rss_limit_mb=2560', '-runs=100'], [testcase_path], result.command) self.assertIn( 'ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000', result.output)
def test_cleanse(self): """Tests cleanse.""" testcase_path, _ = setup_testcase_and_corpus('aaaa', 'empty_corpus') cleanse_output_path = os.path.join(TEMP_DIR, 'cleansed_testcase') engine_impl = engine.LibFuzzerEngine() target_path = engine_common.find_fuzzer_path(ANDROID_DATA_DIR, 'crash_with_A_fuzzer') result = engine_impl.cleanse(target_path, [], testcase_path, cleanse_output_path, 30) self.assertTrue(result) self.assertTrue(os.path.exists(cleanse_output_path)) with open(cleanse_output_path) as f: result = f.read() self.assertFalse(all(c == 'A' for c in result))
def test_minimize(self): """Tests minimize.""" testcase_path, _ = setup_testcase_and_corpus('aaaa', 'empty_corpus') minimize_output_path = os.path.join(TEMP_DIR, 'minimized_testcase') engine_impl = engine.LibFuzzerEngine() target_path = engine_common.find_fuzzer_path(ANDROID_DATA_DIR, 'crash_with_A_fuzzer') result = engine_impl.minimize_testcase(target_path, [], testcase_path, minimize_output_path, 30) self.assertTrue(result) self.assertTrue(os.path.exists(minimize_output_path)) with open(minimize_output_path) as f: result = f.read() self.assertEqual('A', result)
def test_cleanse(self): """Tests cleanse.""" testcase_path, _ = setup_testcase_and_corpus("aaaa", "empty_corpus") cleanse_output_path = os.path.join(TEMP_DIR, "cleansed_testcase") engine_impl = engine.LibFuzzerEngine() target_path = engine_common.find_fuzzer_path(DATA_DIR, "crash_with_A_fuzzer") result = engine_impl.cleanse(target_path, [], testcase_path, cleanse_output_path, 120) self.assertTrue(result) self.assertTrue(os.path.exists(cleanse_output_path)) with open(cleanse_output_path) as f: result = f.read() self.assertFalse(all(c == "A" for c in result))
def test_minimize(self): """Tests minimize.""" testcase_path, _ = setup_testcase_and_corpus("aaaa", "empty_corpus") minimize_output_path = os.path.join(TEMP_DIR, "minimized_testcase") engine_impl = engine.LibFuzzerEngine() target_path = engine_common.find_fuzzer_path(DATA_DIR, "crash_with_A_fuzzer") result = engine_impl.minimize_testcase(target_path, [], testcase_path, minimize_output_path, 120) self.assertTrue(result) self.assertTrue(os.path.exists(minimize_output_path)) with open(minimize_output_path) as f: result = f.read() self.assertEqual("A", result)
def test_fuzz_crash(self): """Tests fuzzing (crash).""" self.mock.get_fuzz_timeout.return_value = get_fuzz_timeout(5.0) _, corpus_path = setup_testcase_and_corpus("empty", "corpus") engine_impl = engine.LibFuzzerEngine() target_path = engine_common.find_fuzzer_path(ANDROID_DATA_DIR, "always_crash_fuzzer") options = engine_impl.prepare(corpus_path, target_path, ANDROID_DATA_DIR) results = engine_impl.fuzz(target_path, options, TEMP_DIR, 10) self.assert_has_stats(results.stats) self.assertEqual( [ self.adb_path, "shell", self.hwasan_options, self.device_path(target_path), "-max_len=100", "-timeout=25", "-rss_limit_mb=2560", "-artifact_prefix=" + self.device_path(TEMP_DIR) + "/", "-max_total_time=5", "-print_final_stats=1", self.device_path(os.path.join(TEMP_DIR, "temp-1337/new")), self.device_path(os.path.join(TEMP_DIR, "corpus")), ], results.command, ) self.assertEqual(1, len(results.crashes)) self.assertTrue(os.path.exists(results.crashes[0].input_path)) self.assertEqual(TEMP_DIR, os.path.dirname(results.crashes[0].input_path)) self.assertEqual(results.logs, results.crashes[0].stacktrace) self.assertListEqual(["-rss_limit_mb=2560", "-timeout=60"], results.crashes[0].reproduce_args) self.assertIn( "Test unit written to {0}/crash-".format( self.device_path(self.crash_dir)), results.logs, ) self.assertIn( "ERROR: HWAddressSanitizer: SEGV on unknown address " "0x000000000000", results.logs, )
def test_exit_failure_logged(self): """Test that we log when libFuzzer's exit code indicates it ran into an error.""" test_helpers.patch(self, [ 'metrics.logs.log_error', ]) _, corpus_path = setup_testcase_and_corpus('empty', 'corpus_with_some_files') os.environ['EXIT_FUZZER_CODE'] = '1' target_path = engine_common.find_fuzzer_path(DATA_DIR, 'exit_fuzzer') engine_impl = engine.LibFuzzerEngine() options = engine_impl.prepare(corpus_path, target_path, DATA_DIR) engine_impl.fuzz(target_path, options, TEMP_DIR, 10) self.assertEqual(1, self.mock.log_error.call_count)
def test_fuzz_crash(self): """Tests fuzzing (crash).""" self.mock.get_fuzz_timeout.return_value = get_fuzz_timeout(5.0) _, corpus_path = setup_testcase_and_corpus('empty', 'corpus') engine_impl = engine.LibFuzzerEngine() target_path = engine_common.find_fuzzer_path(ANDROID_DATA_DIR, 'always_crash_fuzzer') options = engine_impl.prepare(corpus_path, target_path, ANDROID_DATA_DIR) results = engine_impl.fuzz(target_path, options, TEMP_DIR, 10) self.assert_has_stats(results.stats) self.assertEqual([ self.adb_path, 'shell', self.ld_library_path, self.hwasan_options, self.device_path(target_path), '-max_len=100', '-timeout=25', '-rss_limit_mb=2048', '-artifact_prefix=' + self.device_path(TEMP_DIR) + '/', '-max_total_time=5', '-print_final_stats=1', self.device_path(os.path.join(TEMP_DIR, 'temp-1337/new')), self.device_path(os.path.join(TEMP_DIR, 'corpus')), ], results.command) self.assertEqual(1, len(results.crashes)) self.assertTrue(os.path.exists(results.crashes[0].input_path)) self.assertEqual(TEMP_DIR, os.path.dirname(results.crashes[0].input_path)) self.assertEqual(results.logs, results.crashes[0].stacktrace) self.assertListEqual([ '-rss_limit_mb=2048', '-timeout=60', ], results.crashes[0].reproduce_args) self.assertIn( 'Test unit written to {0}/crash-'.format( self.device_path(self.crash_dir)), results.logs) self.assertIn( 'ERROR: HWAddressSanitizer: SEGV on unknown address ' '0x000000000000', results.logs)
def test_fuzz_crash(self): """Test fuzzing that results in a crash.""" _, corpus_path = setup_testcase_and_corpus("empty", "corpus") engine_impl = engine.HonggfuzzEngine() target_path = engine_common.find_fuzzer_path(DATA_DIR, "always_crash_fuzzer") options = engine_impl.prepare(corpus_path, target_path, DATA_DIR) results = engine_impl.fuzz(target_path, options, TEMP_DIR, 10) self.assertListEqual( [ os.path.join(DATA_DIR, "honggfuzz"), "-n", "1", "--exit_upon_crash", "-v", "-z", "-P", "-S", "--rlimit_rss", "2560", "--timeout", "25", "--input", os.path.join(TEMP_DIR, "corpus"), "--workspace", TEMP_DIR, "--run_time", "10", "--", target_path, ], results.command, ) self.assertIn("Seen a crash. Terminating all fuzzing threads", results.logs) self.assertEqual(1, len(results.crashes)) crash = results.crashes[0] self.assertEqual(TEMP_DIR, os.path.dirname(crash.input_path)) self.assertIn("ERROR: AddressSanitizer: heap-use-after-free", crash.stacktrace) with open(crash.input_path) as f: self.assertEqual("A", f.read()[0]) self.assert_has_stats(results)
def test_single_testcase_crash(self): """Tests libfuzzer with a crashing testcase.""" testcase_path, _ = setup_testcase_and_corpus('crash', 'empty_corpus') engine_impl = engine.LibFuzzerEngine() target_path = engine_common.find_fuzzer_path(ANDROID_DATA_DIR, 'test_fuzzer') result = engine_impl.reproduce(target_path, testcase_path, ['-timeout=60', '-rss_limit_mb=2560'], 65) self.assertEqual([ self.adb_path, 'shell', self.hwasan_options, self.device_path(target_path), '-timeout=60', '-rss_limit_mb=2560', '-runs=100', self.device_path(testcase_path) ], result.command) self.assertIn( 'ERROR: HWAddressSanitizer: SEGV on unknown address 0x000000000000', result.output)
def test_exit_target_bug_not_logged(self, exit_code): """Test that we don't log when exit code indicates bug found in target.""" test_helpers.patch(self, [ 'metrics.logs.log_error', ]) def mocked_log_error(*args, **kwargs): # pylint: disable=unused-argument self.assertNotIn(engine.ENGINE_ERROR_MESSAGE, args) self.mock.log_error.side_effect = mocked_log_error _, corpus_path = setup_testcase_and_corpus('empty', 'corpus_with_some_files') os.environ['EXIT_FUZZER_CODE'] = exit_code target_path = engine_common.find_fuzzer_path(DATA_DIR, 'exit_fuzzer') engine_impl = engine.LibFuzzerEngine() options = engine_impl.prepare(corpus_path, target_path, DATA_DIR) engine_impl.fuzz(target_path, options, TEMP_DIR, 10)