def apply_rebuild_revert(binary, args, crash_file, ltrace_pattern, patches, \ on_stdin=False): successful_patches = [] applied_patches = [] # apply all valid_patches for file_to_patch, patch in patches: patch = apply_possible_fixing_patch(file_to_patch, patch) if patch: applied_patches.append((file_to_patch, patch)) status = os.system('./9-rebuild.sh > /dev/null') result = os.WEXITSTATUS(status) if result != 0: print "REBUILD apply_rebuild_revert failed" # revert all patches for file_to_patch, patch in applied_patches: revert_patch(file_to_patch, patch) # by construction, this cannot fail return [] # no successful patches if on_stdin: exit, ltrace_output = run_ltrace_stdin(binary, args, crash_file, ltrace_pattern) else: exit, ltrace_output = run_ltrace(binary, args, crash_file, ltrace_pattern) if not crash_signal.did_crash(ltrace_output[-1]): print '[+] SUCCESS - Program no longer crashes' print '[+] Patch:\n', patch.text if TEST: record_test_output('[+] SUCCESS - Program no longer crashes\n') record_test_output('[+] Patch:\n' + '\n'.join(patch.text.split('\n'))) print 'successful patches equals applied: %d' % len(applied_patches) successful_patches = applied_patches else: print '[-] Fail: still crashes.' if TEST: record_test_output('[-] Fail: still crashes.\n') successful_patches = [] # revert all patches for file_to_patch, patch in applied_patches: revert_patch(file_to_patch, patch) # by construction, this cannot fail if len(successful_patches) == 0: return [] else: successful_patches = applied_patches return successful_patches
def run(binary, crash_file, args, \ addr2line_offset, range_backward, range_forward, \ bug_kind, source_dir, on_stdin, patch_path="p.patch", \ line_num_offset=0): success = False # successfully removes the crash for the crash_file successful_patches = [] if bug_kind == "memcpy": ltrace_pattern = "[email protected]*" match_template = "memcpy(:[1], :[2], :[_]);" rewrite_template = \ """ // ROOIBOS START memcpy(:[1], :[2], 1); // ROOIBOS END """ elif bug_kind == "strcpy": ltrace_pattern = "[email protected]*" match_template = "strcpy(:[1], :[2]);" rewrite_template = \ """ // ROOIBOS START strncpy(:[1], :[2], 1); :[1][1] = 0; // ROOIBOS END """ else: print "Unknown bug kind %s" % bug_kind assert (False) if on_stdin: exit, ltrace_output = run_ltrace_stdin(binary, args, crash_file, ltrace_pattern) else: exit, ltrace_output = run_ltrace(binary, args, crash_file, ltrace_pattern) valid_patches = [] print 'check did crash' print 'ltrace_output', ltrace_output if crash_signal.did_crash(ltrace_output[-1]): print 'YES' mmap = dump_memory_map(binary, args, crash_file) ltrace_output = ltrace_output[::-1] patch_locations = process_ltrace(ltrace_output, mmap) print 'ltraced' patch_locations_tmp = [] for patch_location in patch_locations: try: # skip cases where there's no int at the end (like 'discriminator') m = re.search('(.*):(.*)', patch_location) if m.group(1) and m.group(2): file_to_patch = m.group(1) line_num = m.group(2) line_num = int(line_num) patch_locations_tmp.append((file_to_patch, line_num)) except: print 'Discriminator @', file_to_patch, line_num pass patch_locations = patch_locations_tmp if DEBUG_PATCH_LOCATIONS: print '~=~= patch locations ~=~=' print '\n'.join( map(lambda x: "%s:%d" % (x[0], x[1]), patch_locations)) for file_to_patch, line_num in patch_locations: zero_offset = -1 line_num = line_num + zero_offset line_num = line_num + addr2line_offset patch = generate_replacement_patch(\ file_to_patch, \ line_num, \ range_backward, \ range_forward, \ match_template, \ rewrite_template) if patch: valid_patches.append((file_to_patch, patch)) for i, valid_patch in enumerate(valid_patches): successful_patches = apply_rebuild_revert(\ binary, \ args, \ crash_file, \ ltrace_pattern, \ [valid_patch], \ on_stdin=on_stdin) # multiple patches fix this bug if successful_patches > 1 # for strcpy, etc, we are traversing from the last to first # in trace for j, (file_to_patch, successful_patch) in enumerate(successful_patches): print "SUCCESSFUL PATCH %s\n" % successful_patch.text if DUMP_ALL_PATCHES: dump_patch(patch_path + '_' + str(i) + '_' + str(j), successful_patch.text) else: # return the first one dump_patch(patch_path, successful_patch.text) os.system('./9-rebuild.sh > /dev/null') return True if len(successful_patches) > 0: success = True os.system('./9-rebuild.sh > /dev/null') return success
rewrite_template = \ """ // ROOIBOS START memcpy(:[1], :[2], 1); // ROOIBOS END """ else: print "Unknown bug kind %s" % bug_kind assert(False) exit,ltrace_output = run_ltrace(binary, args, crash_file, ltrace_pattern) valid_patches = [] # check last line if we crashed if crash_signal.did_crash(ltrace_output[-1]): mmap = dump_memory_map(binary, args, crash_file) # if we did, reverse the trace and start processing from the end ltrace_output = ltrace_output[::-1] patch_locations = process_ltrace(ltrace_output,mmap) # filter valid locations by regex patch_locations_tmp = [] for patch_location in patch_locations: m = re.search('(.*):(.*)', patch_location) if m.group(1) and m.group(2): file_to_patch = m.group(1) line_num = m.group(2) line_num = int(line_num) patch_locations_tmp.append((file_to_patch,line_num))