def move_mergeable_units(merge_directory, corpus_directory): """Move new units in |merge_directory| into |corpus_directory|.""" initial_units = set( os.path.basename(filename) for filename in shell.get_files_list(corpus_directory)) for unit_path in shell.get_files_list(merge_directory): unit_name = os.path.basename(unit_path) if unit_name in initial_units and is_sha1_hash(unit_name): continue dest_path = os.path.join(corpus_directory, unit_name) shell.move(unit_path, dest_path)
def legalize_corpus_files(directory): """Convert the name of every corpus file in |directory| to a name that is allowed on Windows.""" # Iterate through return value of legalize_filenames to convert every # filename. files_list = shell.get_files_list(directory) legalize_filenames(files_list)
def find_mutator_plugin(): """Sets LD_PRELOAD to the path of a usable mutator plugin shared object. This should only be called after a call to get_mutator_plugin.""" paths = shell.get_files_list(_get_mutator_plugins_unpacked_dir()) # This function should not be called unless there is an unpacked plugin. for path in paths: if os.path.basename(path) == MUTATOR_SHARED_OBJECT_FILENAME: return path return None
def generate_new_testcase_mutations_using_radamsa( corpus_directory, new_testcase_mutations_directory, generation_timeout): """Generate new testcase mutations based on Radamsa.""" radamsa_path = get_radamsa_path() if not radamsa_path: # Mutations using radamsa are not supported on current platform, bail out. return radamsa_runner = new_process.ProcessRunner(radamsa_path) files_list = shell.get_files_list(corpus_directory) filtered_files_list = [ f for f in files_list if os.path.getsize(f) <= CORPUS_INPUT_SIZE_LIMIT ] if not filtered_files_list: # No mutations to do on an empty corpus or one with very large files. return old_corpus_size = shell.get_directory_file_count( new_testcase_mutations_directory) expected_completion_time = time.time() + generation_timeout for i in range(RADAMSA_MUTATIONS): original_file_path = random_choice(filtered_files_list) original_filename = os.path.basename(original_file_path) output_path = os.path.join( new_testcase_mutations_directory, get_radamsa_output_filename(original_filename, i)) result = radamsa_runner.run_and_wait( ['-o', output_path, original_file_path], timeout=RADAMSA_TIMEOUT) if (os.path.exists(output_path) and os.path.getsize(output_path) > CORPUS_INPUT_SIZE_LIMIT): # Skip large files to avoid furthur mutations and impact fuzzing # efficiency. shell.remove_file(output_path) elif result.return_code or result.timed_out: logs.log_warn('Radamsa failed to mutate or timed out.', output=result.output) # Check if we exceeded our timeout. If yes, do no more mutations and break. if time.time() > expected_completion_time: break new_corpus_size = shell.get_directory_file_count( new_testcase_mutations_directory) logs.log('Added %d tests using Radamsa mutations.' % (new_corpus_size - old_corpus_size))
def unpack_seed_corpus_if_needed( fuzz_target_path, corpus_directory, max_bytes=float("inf"), force_unpack=False, max_files_for_unpack=MAX_FILES_FOR_UNPACK, ): """If seed corpus available, unpack it into the corpus directory if needed, ie: if corpus exists and either |force_unpack| is True, or the number of files in corpus_directory is less than |max_files_for_unpack|. Uses |fuzz_target_path| to find the seed corpus. If max_bytes is specified, then seed corpus files larger than |max_bytes| will not be unpacked. """ seed_corpus_archive_path = get_seed_corpus_path(fuzz_target_path) if not seed_corpus_archive_path: return num_corpus_files = len(shell.get_files_list(corpus_directory)) if not force_unpack and num_corpus_files > max_files_for_unpack: return if force_unpack: logs.log("Forced unpack: %s." % seed_corpus_archive_path) archive_iterator = archive.iterator(seed_corpus_archive_path) # Unpack seed corpus recursively into the root of the main corpus directory. idx = 0 for seed_corpus_file in archive_iterator: # Ignore directories. if seed_corpus_file.name.endswith("/"): continue # Allow callers to opt-out of unpacking large files. if seed_corpus_file.size > max_bytes: continue output_filename = "%016d" % idx output_file_path = os.path.join(corpus_directory, output_filename) with open(output_file_path, "wb") as file_handle: shutil.copyfileobj(seed_corpus_file.handle, file_handle) idx += 1 logs.log("Unarchiving %d files from seed corpus %s." % (idx, seed_corpus_archive_path))
def generate_new_testcase_mutations_using_radamsa( corpus_directory, new_testcase_mutations_directory, expected_completion_time): """Generate new testcase mutations based on Radamsa.""" radamsa_path = get_radamsa_path() if not radamsa_path: # Mutations using radamsa are not supported on current platform, bail out. return radamsa_runner = new_process.ProcessRunner(radamsa_path) files_list = shell.get_files_list(corpus_directory) if not files_list: # No mutations to do on an empty corpus, bail out. return old_corpus_size = shell.get_directory_file_count( new_testcase_mutations_directory) for i in range(RADAMSA_MUTATIONS): original_file_path = engine_common.random_choice(files_list) original_filename = os.path.basename(original_file_path) output_path = os.path.join( new_testcase_mutations_directory, 'radamsa-%08d-%s' % (i + 1, original_filename)) result = radamsa_runner.run_and_wait( ['-o', output_path, original_file_path], timeout=RADAMSA_TIMEOUT) if result.return_code or result.timed_out: logs.log_error('Radamsa failed to mutate or timed out.', output=result.output) # Check if we exceeded our timeout. If yes, do no more mutations and break. if time.time() > expected_completion_time: break new_corpus_size = shell.get_directory_file_count( new_testcase_mutations_directory) logs.log('Added %d tests using Radamsa mutations.' % (new_corpus_size - old_corpus_size))