def record_progress(args, total_tc, total_pm_tc, total_paths, total_pm_paths, exec_rate, mq_pop): if args.progress_file != None: # Create the file if not os.path.isfile(args.progress_file): with open(args.progress_file, 'w') as obj: obj.write('') interval = args.progress_interval tail_cmd = ['tail', '-1', args.progress_file] last_line = subprocess.check_output(tail_cmd).decode("utf-8") last_write = last_line.split(',')[0] if last_write.strip() == '': last_write = 0 else: last_write = int(last_write) cur_time = int(time.time()) if (cur_time - last_write) < 0: common.abort('Corrupted progress file: ' + args.progress_file) if (cur_time - last_write) > interval: with open(args.progress_file, 'a') as obj: obj.write(str(cur_time) + ',' + str(total_tc) + ',' \ + str(total_pm_tc) + ',' + str(total_paths) + ','\ + str(total_pm_paths) + ',' + str(exec_rate) + ','\ + str(mq_pop) + '\n')
def iter_id(self): """ Returns the highest iter_id for the highest stage in the outdir, requires a call to sync() before the first use. Each subsequent calls would require sync() calls to retrieve latest `outdir` state. """ if not hasattr(self, '_iter_id'): common.abort('No state found, was sync() called?') return self._iter_id
def dedup_exists(self): """ Returns boolean value denoting the existence of deduplication directory in the outdir, requires a call to sync() before the first use. Each subsequent calls would require sync() calls to retrieve lates `outdir` state. """ if not hasattr(self, '_dedup_exists'): common.abort('No state found, was sync() called?') return self._dedup_exists
def except_hook(exctype, value, tb): tb_fmt = traceback.format_exception(exctype, value, tb)[1:-1] # Too many open files if '[Errno 24]' in str(value): print('Open files:') list_open_fd() common.abort('Exception raised: ' + exctype.__name__ + ': ' + str(value), tb_fmt=tb_fmt)
def run_failure_inj(cfg, tgtcmd, imgpath, testcase_f, clean_name, create, verbose=False): """ @brief Run failure injection on an image @param create If true, inject the failure to the process of creating the image @return None""" if not create and not os.path.isfile(imgpath): abort('Image path %s does not exist' % imgpath) env, cmd = gen_failure_inj_cmd(cfg, cfg.tgtcmd, imgpath, create, verbose) env.update({"FI_IMG_SUFFIX": clean_name.replace('.testcase', '')}) if verbose: printv('Failure Injection:') printv('%20s : %s' % ('env', str(env))) printv('%20s : %s' % ('cmd', ' '.join(cmd))) printv('%20s : %s' % ('stdin', testcase_f)) fd, out_file = tempfile.mkstemp(prefix='pmfuzz-img-gen-out-') printv('Redirecting output to ' + out_file) exit_code = None with open(out_file, 'w') as stdout, open(testcase_f, 'r') as stdin: exit_code = exec_shell( cmd=cmd, stdin=stdin, stdout=stdout, stderr=subprocess.STDOUT, env=env, wait=True, timeout= 30 # Set a generous timeout of 30 seconds so things don't crash ) os.close(fd) descr_str, success = translate_exit_code(exit_code) if not success: abort('Failure injection for pid %d failed: %s' \ % (os.getpid(), descr_str))
def test_img_gen(self, imgpath): """ @brief Tests the process of creating a new image with the testcase by checking return code of the target @param imgpath str representing the complete path of the image to test, the path should not exist @return bool value indicating success """ # Create a tempfile for writing run output fd, tmp = tempfile.mkstemp(prefix='pmfuzz-test-img-output-') os.close(fd) tgtcmd_loc = list(self.cfg.tgtcmd) imgpath, tgtcmd_loc = nh.set_img_path(tgtcmd_loc, imgpath, self.cfg) env = self.cfg.get_env(persist=False) if self.verbose: printv('Writing run output to ' + tmp) success, exit_code = None, None with open(tmp, 'w') as out: with open(self.testcase_f, 'r') as testcase_obj: exit_code = exec_shell( cmd = tgtcmd_loc, stdin = testcase_obj, stdout = out, stderr = subprocess.STDOUT, env = env, wait = True ) code_desc, success = translate_exit_code(exit_code) if not success and self.verbose: printv('Image failed.') if success == None: abort('Test run failed, unable to check image.') return success, exit_code, tgtcmd_loc, env
def perform_checks(): """ @brief Performs a series of checks to make sure basic AFL requirements are met @return None """ # Check for core dump notification printi('Checking for core dump notification') with open('/proc/sys/kernel/core_pattern', 'r') as obj: content = obj.read().strip() if content != 'core': print() printi( 'Run "sudo bash -c \'echo core >/proc/sys/kernel/core_pattern\'"', format_path=False) common.abort('Incorrectly configured core dump notifications') # Check if ASLR is enabled printi('Checking for ASLR') with open('/proc/sys/kernel/randomize_va_space', 'r') as obj: content = obj.read().strip() if content != '0': print() printi( 'Run "sudo bash -c \'echo 0 >/proc/sys/kernel/randomize_va_space\'"', format_path=False) common.abort( 'ASLR should be disabled for image deduplication to work.') printi('Checking for Python version') PY_MAJOR = sys.version_info[0] PY_MINOR = sys.version_info[1] if (PY_MAJOR != 3 or PY_MINOR < 6): common.abort("Python 3.6+ required.")
def gen_img(self, dest_dir, compress_img=True, img_path=None): """ @brief Generate image for a testcase file @param testcase_f str that points to the testcase to use for generation @param dest_dir str Directory to store the resulting image @param tgtcmd List of str for the command for running the target prog @param cfg Config for setting up the target process' environment @return None """ testcase_f = self.testcase_f cfg = self.cfg verbose = self.verbose tgtcmd = cfg.tgtcmd tgtcmd_loc = None if img_path == None: img_name = path.basename(nh.get_metadata_files(testcase_f)['pm_pool']) # Get the command for generating the image img_path, tgtcmd_loc = nh.set_img_name(tgtcmd, img_name, cfg) abort_if(img_path=='', 'Unable to parse image path, tgtcmd=' + \ str(tgtcmd) + ', img_name=' + img_name) else: img_name = path.basename(img_path) # Get the command for generating the image img_path, tgtcmd_loc = nh.set_img_path(tgtcmd, img_path, cfg) abort_if(img_path=='', 'Unable to parse image path, tgtcmd=' + \ str(tgtcmd) + ', img_name=' + img_name) # Enable persistence for image in the environment env = cfg.get_env(persist=True) if verbose: printv('cmd: %s' % (' '.join(tgtcmd_loc))) printv('env: %s' % (str(env))) printv('stdin: %s' % testcase_f) # Create a tempfile for writing run output fd, tmp = tempfile.mkstemp(prefix='pmfuzz-img-gen-output-') os.close(fd) if verbose: printv('Writing image generation output to ' + tmp) with open(tmp, 'w') as out: with open(testcase_f, 'r') as testcase_obj: exit_code = exec_shell( cmd=tgtcmd_loc, stdin=testcase_obj, stdout=out, stderr=subprocess.STDOUT, env=env, wait=True, timeout = 30 # Set a generous timeout of 30 seconds so things don't crash ) code_desc, success = translate_exit_code(exit_code) if not success: abort('Image generation failed: ' + code_desc) if not path.isfile(img_path): abort('Image generation failed (%s).' % img_path) # Copy the file back to the pmfuzz result directory if compress_img: src = img_path dest = path.join(dest_dir, path.basename(img_path)) dest = nh.get_metadata_files(dest)['pm_cmpr_pool'] compress(src, dest, verbose) remove(src) if verbose: printw('Deleting: ' + src)