diff --git a/conf-fuzz-env.sh b/conf-fuzz-env.sh new file mode 100755 index 0000000000..555df70781 --- /dev/null +++ b/conf-fuzz-env.sh @@ -0,0 +1,9 @@ +export PYTHONPATH=/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill +export AFL_NO_STARTUP_CALIBRATION=1 +export AFL_DEBUG=1 +export AFL_SKIP_CPUFREQ=1 +export AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 +export AFL_PYTHON_MODULE=example +export PD_ENABLE_TAP=1 + +echo "Configured 6 environmment variables" \ No newline at end of file diff --git a/custom_mutators/packetdrill/.gitignore b/custom_mutators/packetdrill/.gitignore new file mode 100644 index 0000000000..43d47950b1 --- /dev/null +++ b/custom_mutators/packetdrill/.gitignore @@ -0,0 +1,2 @@ +/fuzz_in*/ +/fuzz_udp_in \ No newline at end of file diff --git a/custom_mutators/packetdrill/common.py b/custom_mutators/packetdrill/common.py new file mode 100644 index 0000000000..44a5056ad8 --- /dev/null +++ b/custom_mutators/packetdrill/common.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +Module containing functions shared between multiple AFL modules + +@author: Christian Holler (:decoder) + +@license: + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. + +@contact: choller@mozilla.com +""" + +from __future__ import print_function +import random +import os +import re + + +def randel(l): + if not l: + return None + return l[random.randint(0, len(l) - 1)] + + +def randel_pop(l): + if not l: + return None + return l.pop(random.randint(0, len(l) - 1)) + + +def write_exc_example(data, exc): + exc_name = re.sub(r"[^a-zA-Z0-9]", "_", repr(exc)) + + if not os.path.exists(exc_name): + with open(exc_name, "w") as f: + f.write(data) diff --git a/custom_mutators/packetdrill/example.py b/custom_mutators/packetdrill/example.py new file mode 100644 index 0000000000..56ec9d91bd --- /dev/null +++ b/custom_mutators/packetdrill/example.py @@ -0,0 +1,423 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +Example Python Module for AFLFuzz + +@author: Christian Holler (:decoder) + +@license: + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. + +@contact: choller@mozilla.com +""" + +import calendar +import time +import random +import struct +import re +import sys +import os +import binascii + + +iter_index = 0 +debug = 0 + +def init(seed): + """ + Called once when AFLFuzz starts up. Used to seed our RNG. + + @type seed: int + @param seed: A 32-bit random value + """ + #random.seed(seed) + + +def deinit(): + pass + +def debug_print(msg): + if debug: + print(msg) + +def get_pd_commands_from_script(filename): + + try: + with open(filename, "r") as pd_script: + pd_commands = pd_script.readlines(); + + pruned_commands = [command for command in pd_commands if (command.strip() != "" and not command.startswith("//"))]; + + return pruned_commands; + + except: + debug_print("Exception while opening the file"); + return []; + +tcp_fields = [ + {"name": "src_port", "no_bytes": 2}, + {"name": "dst_port", "no_bytes": 2}, + {"name": "seq_num", "no_bytes": 4}, + {"name": "ack_num", "no_bytes": 4}, + {"name": "tcp_hdr_len", "no_bytes": 1}, + {"name": "flags", "no_bytes": 1}, + {"name": "win_size", "no_bytes": 2}, + {"name": "tcp_checksum", "no_bytes": 2}, + {"name": "urg_pointer", "no_bytes": 2} +] + +#fields = ["src_port","ack", "win", "mss"]; + +def generate_replace_tcp_inst(buf, current_counter): + + field_index = buf[current_counter] % len(tcp_fields); + + current_counter += 1; + + field_dict = tcp_fields[field_index]; + + if (current_counter + field_dict["no_bytes"] > len(buf)): + return current_counter - 1, "" + + src_port_bytes: bytearray = buf[current_counter: current_counter + field_dict["no_bytes"]]; + inst = "rep tcp " + field_dict["name"] + " 0x" + src_port_bytes.hex().capitalize(); + current_counter += field_dict["no_bytes"]; + + return current_counter, inst; + + +ip_fields = [ + {"name": "version_ihl", "no_bytes": 1}, + {"name": "dscp_esn", "no_bytes": 1}, + {"name": "tot_len", "no_bytes": 2}, + {"name": "iden", "no_bytes": 2}, + {"name": "flags_fragoff", "no_bytes": 2}, + {"name": "ttl", "no_bytes": 1}, + {"name": "protocol", "no_bytes": 1}, + {"name": "ip_checksum", "no_bytes": 2}, + {"name": "src_ip", "no_bytes": 4}, + {"name": "dest_ip", "no_bytes": 4} +] + +def generate_replace_ip_inst(buf, current_counter): + + field_index = buf[current_counter] % len(ip_fields); + + current_counter += 1; + + field_dict = ip_fields[field_index]; + + if (current_counter + field_dict["no_bytes"] > len(buf)): + return current_counter - 1, "" + + rep_bytes: bytearray = buf[current_counter: current_counter + field_dict["no_bytes"]]; + inst = "rep ipv4 " + field_dict["name"] + " 0x" + rep_bytes.hex().capitalize(); + current_counter += field_dict["no_bytes"]; + + return current_counter, inst; + + +MAX_INSERT_BYTES = 4; + +MAX_DELETE_BYTES = 6; + +MAX_INSERT_POINT = 20; + +def generate_insert_random(buf, current_counter): + + insert_point = buf[current_counter] % MAX_INSERT_POINT; + + current_counter += 1; + + num_insert_butes = buf[current_counter] % MAX_INSERT_BYTES; + + current_counter += 1; + + insert_bytes: bytearray = buf[current_counter: current_counter + num_insert_butes]; + + if (len(insert_bytes) == 0): + return current_counter - 2, ""; + + insert_bytes = insert_bytes.hex().capitalize(); + + current_counter += num_insert_butes; + + return current_counter, f"ins tcp {insert_point} 0x{insert_bytes}"; + +insert_types = ["tcp_option", "ipv4_option", "random_bytes"] + +def generate_insert_inst(buf, current_counter): + + if (len(buf) < current_counter + 7): + return current_counter, "" + + insert_type_idx = buf[current_counter] % len(insert_types); + current_counter += 1; + + if (insert_type_idx == 0): + return generate_insert_tcp_option(buf, current_counter); + elif (insert_type_idx == 1): + return generate_insert_IPv4_option(buf, current_counter) + else: + return generate_insert_random(buf, current_counter); + +NUM_TCP_KINDS = 5 +MAX_TCP_LEN = 3 + +def generate_insert_tcp_option(buf, current_counter): + + option_kind = buf[current_counter] % NUM_TCP_KINDS + current_counter += 1 + option_len = buf[current_counter] % MAX_TCP_LEN + current_counter += 1 + option_values = buf[current_counter: current_counter + option_len] + current_counter += option_len + + #debug_print(f"option_kind: {option_kind} \n option_len: {option_len} \n option_values: {option_values}") + + option_kind_hex = "{:02x}".format(option_kind) + option_len_hex = "{:02x}".format(option_len) + option_values_hex = option_values.hex() + + return current_counter, f"ins tcp 20 0x{option_kind_hex}{option_len_hex}{option_values_hex}" + +NUM_IP_KINDS = 5 +MAX_IP_OPTION_LEN = 3 + +def generate_insert_IPv4_option(buf, current_counter): + + option_kind = buf[current_counter] % NUM_IP_KINDS + current_counter += 1 + option_len = buf[current_counter] % MAX_IP_OPTION_LEN + current_counter += 1 + option_values = buf[current_counter: current_counter + option_len] + current_counter += option_len + + option_len_value = option_len + 2 + + #debug_print(f"option_kind: {option_kind} \n option_len: {option_len_value} \n option_values: {option_values}") + + option_kind_hex = "{:02x}".format(option_kind) + option_len_hex = "{:02x}".format(option_len_value) + option_values_hex = option_values.hex() + + return current_counter, f"ins ipv4 20 0x{option_kind_hex}{option_len_hex}{option_values_hex}" + + +def generate_truncate_tcp_header_inst(buf, current_counter): + + return current_counter, f"trun tcp 0 20" + + +def generate_delete_inst(buf, current_counter): + + delete_point = buf[current_counter]; + + current_counter += 1; + + num_truncate_bytes = buf[current_counter] % MAX_INSERT_BYTES; + + current_counter += 1; + + return current_counter, f"trun tcp {delete_point} {num_truncate_bytes}"; + + +tcp_states = [ + ("ESTABLISHED", "/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/templates/fuzz-template-tcp-established.pkt", 9), + ("ESTABLISHED-OPTION", "/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/templates/fuzz-template-tcp-established-option.pkt", 9), + ("LISTEN", "/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/templates/fuzz-template-tcp-listen.pkt", 5), + ("SEND", "/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/templates/fuzz-template-tcp-send.pkt", 11), + ("SYN_RECEIVED", "/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/templates/fuzz-template-tcp-syn-rcvd.pkt", 8), + ("SYN_SENT", "/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/templates/fuzz-template-tcp-syn-sent.pkt", 4), + ("LAST_ACK", "/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/templates/fuzz-template-tcp-last-ack.pkt", 10), + ("FIN_WAIT", "/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/templates/fuzz-template-tcp-fin-wait.pkt", 12) +] + +udp_states = [ + ("SOCKET_OPEN", "/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/udp_templates/fuzz_template_socket_open.pkt", 5), + ("SOCKET_CLOSED", "/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/udp_templates/fuzz_template_socket_closed.pkt", 1) +] + +opcodes = [ +(0, "REP_TCP_SEQ_NUM", "rep tcp seq_num", True), +(1, "REP_TCP_ACK_NUM", "rep tcp ack_num", True), +(2, "INS_TCP_OPTION", "ins tcp 20", True), +(3, "REP_TCP_FLAGS", "rep tcp flags", True), +(4, "REP_TCP_WIN_SIZE", "rep tcp win_size", True), +(5, "REP_TCP_SRC_PORT", "rep tcp src_port", True), +(6, "REP_TCP_DEST_PORT", "rep tcp dest_port", True), +(7, "REP_TCP_HEADER_LENGTH", "rep tcp tcp_hdr_len", True), +(8, "REP_IPV4_VERSION_IHL", "rep ipv4 version_ihl", True), +(9, "REP_IPV4_DSCP_ECN", "rep ipv4 dscp_esn", True), +(10, "REP_IPV4_TOT_LEN", "rep ipv4 tot_len", True), +(11, "REP_IPV4_SOURCE_ADDR", "rep ipv4 src_ip", True), +(12, "REP_IPV4_DEST_ADDR", "rep ipv4 dest_ip", True), +(13, "INS_IP_OPTION", "ins ipv4 20", True), +(14, "TRUN_TCP_HEADER", "trun tcp 0", True) +] + +def decode_instruction(bytes_: bytes): + opcode = struct.unpack("!B", bytes_[:1])[0] % len(opcodes) + debug_print(f"opcode {opcode}") + opcode_found = False + for i, op in enumerate(opcodes): + if op[0] == opcode: + opcode_found = True + break + + if opcode_found == False: + return "" + + fuzz_inst = "" + if op[3] == True: + value = bytes_[4:].hex().upper() + if len(value) == 0: + debug_print(f"invalid value: {bytes_.hex().upper()}") + return "" + fuzz_inst = "{" + op[2] + " " + "0x"+value + "}" + else: + value_bytes = bytes_[4:].rjust(4, b'\x00') + value = int.from_bytes(value_bytes, byteorder='big') + fuzz_inst = "{" + op[2] + " " + str(value) + "}" + + return fuzz_inst + + +def post_process(buf): + +# Called just before the execution to write the test case in the format +# expected by the target +# +# @type buf: bytearray +# @param buf: The buffer containing the test case to be executed +# +# @rtype: bytearray +# @return: The buffer containing the test case after + + global iter_index + + if (len(buf) < 4): + return bytes("", "utf-8"); + + # debug_print(f"Fuzz iteration {iter_index}") + + state_idx_to_fuzz = buf[1] % len(tcp_states) + + state_to_fuzz = tcp_states[state_idx_to_fuzz] + iter_index = iter_index + 1 + + pd_commands = get_pd_commands_from_script(state_to_fuzz[1]); + + debug_print(f"STate to fuzz: {state_to_fuzz}") + # debug_print(f"Length of list: {len(pd_commands)}") + + fuzz_index = state_to_fuzz[2] - 1 + + pd_command = pd_commands[fuzz_index] # Possible list index out of bounds + + #updated_commands = pd_commands[:-1] + updated_commands = pd_commands[0: fuzz_index] + + inbound_match = re.search("\+\d*\.?\d* < [S|F|P|\.]?", pd_command); + + if (inbound_match is None): + updated_commands.append(pd_command); + return bytes("", "utf-8") + + try: + inst = decode_instruction(buf) + except: + return bytes("", "utf-8") + + if (inst == ""): + return bytes("", "utf-8") + else: + debug_print(f"Fuzz Instruction: {inst}") + debug_print(f"Script id: {state_idx_to_fuzz} min_length: {buf[2]} max_length: {buf[3]}") + fuzz_instruction = pd_command.strip() + inst + '\n'; + updated_commands.append(fuzz_instruction); + + if (fuzz_index < len(pd_commands) - 1): + updated_commands.extend(pd_commands[fuzz_index + 1 :]) + + updated_command_string = ''.join(updated_commands); + + updated_buf = bytearray(updated_command_string.encode()); + + # timestamp = calendar.timegm(time.gmtime()); + + # mutated_filename = f"afl-pd-{timestamp}.pkt" + + # with open(mutated_filename, "wb") as mutated_files: + # mutated_files.write(updated_buf); + + # pd_command_string = ''.join(pd_commands); + + return updated_buf; + + +if __name__ == "__main__": + + # Check if the user has provided two file paths or a base64 string + if len(sys.argv) == 3: + # Get the file paths from the command line arguments + src_path = sys.argv[1] + dest_folder_path = sys.argv[2] + + # Open the source file for reading + with open(src_path, "rb") as src_file: + # Read the contents of the source file + src_data = src_file.read() + + elif len(sys.argv) == 2: + # Get the base64 string from the command line argument + src_base64 = sys.argv[1] + + # Decode the base64 string into a bytearray + try: + src_data = binascii.unhexlify(src_base64) + except: + print(f"Error: invalid hex string {src_base64}") + exit(1) + + else: + # If not, display an error message and exit + print("Error: please provide either two file paths or a base64 string") + exit(1) + + processed_data = post_process(src_data) + + if (len(processed_data) == 0): + print("Post process retuned empty string") + exit(1) + + if len(sys.argv) == 3: + file_name = os.path.basename(src_path) + dest_file_name = os.path.join(dest_folder_path, file_name + ".pd") + + # Open the destination file for writing + with open(dest_file_name, "w") as dest_file: + # Write the contents of the source file to the destination file + dest_file.write(processed_data.decode("utf-8")) + + # Display a success message + debug_print(f"Successfully written post-processed data to {dest_file_name}") + + elif len(sys.argv) == 2: + # Encode the processed data as base64 and print to stdout + print(binascii.hexlify(processed_data).decode("utf-8")) + + + + + """ buf = b"042af4" + + current_counter, inst = generate_truncate_tcp_header_inst(buf, 0) + + debug_print(f"current counter: {current_counter}") + debug_print("instruction: " + inst) """ + diff --git a/custom_mutators/packetdrill/fuzz-instruction-decoder.py b/custom_mutators/packetdrill/fuzz-instruction-decoder.py new file mode 100644 index 0000000000..68b089e1b8 --- /dev/null +++ b/custom_mutators/packetdrill/fuzz-instruction-decoder.py @@ -0,0 +1,57 @@ +import struct + +opcodes = [ +(0, "REP_TCP_SEQ_NUM", "rep tcp seq_num", True), +(1, "REP_TCP_ACK_NUM", "rep tcp ack_num", True), +(2, "INS_TCP_OPTION", "ins tcp 20", True), +(3, "REP_TCP_FLAGS", "rep tcp flags", True), +(4, "REP_TCP_WIN_SIZE", "rep tcp win_size", True), +(5, "REP_TCP_SRC_PORT", "rep tcp src_port", True), +(6, "REP_TCP_DEST_PORT", "rep tcp dest_port", True), +(7, "REP_TCP_HEADER_LENGTH", "rep tcp tcp_hdr_len", True), +(8, "REP_IPV4_VERSION_IHL", "rep ipv4 version_ihl", True), +(9, "REP_IPV4_DSCP_ECN", "rep ipv4 dscp_esn", True), +(10, "REP_IPV4_TOT_LEN", "rep ipv4 tot_len", True), +(11, "REP_IPV4_SOURCE_ADDR", "rep ipv4 src_ip", True), +(12, "REP_IPV4_DEST_ADDR", "rep ipv4 dest_ip", True), +(13, "INS_IP_OPTION", "ins ipv4 20", True), +(14, "TRUN_TCP_HEADER", "trun tcp 0", True) +] + +def decode_instruction(bytes_: bytes): + opcode = struct.unpack("!B", bytes_[:1])[0] % len(opcodes) + print(f"opcode {opcode}") + opcode_found = False + for i, op in enumerate(opcodes): + if op[0] == opcode: + opcode_found = True + break + + if opcode_found == False: + return "" + + fuzz_inst = "" + if op[3] == True: + value = bytes_[4:].hex().upper() + fuzz_inst = "{" + op[2] + " " + "0x"+value + "}" + else: + value_bytes = bytes_[4:].rjust(4, b'\x00') + value = int.from_bytes(value_bytes, byteorder='big') + fuzz_inst = "{" + op[2] + " " + str(value) + "}" + + return fuzz_inst + +def main(): + with open("/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/fuzz_in_vuln/instruction_0.bin", "rb") as f: + bytes_ = f.read() + print(f"Len bytes: {len(bytes_)}") + instruction = decode_instruction(bytes_) + print(f"Fuzz instruction: {instruction}") + + script_id = struct.unpack("!B", bytes_[1:2])[0] + min_length = struct.unpack("!B", bytes_[2:3])[0] + max_length = bytes_[3] + print(f"Script id: {script_id} min_length: {min_length} max_length: {max_length}") + +if __name__ == "__main__": + main() diff --git a/custom_mutators/packetdrill/fuzz-instruction-encoder.py b/custom_mutators/packetdrill/fuzz-instruction-encoder.py new file mode 100644 index 0000000000..d076b0da14 --- /dev/null +++ b/custom_mutators/packetdrill/fuzz-instruction-encoder.py @@ -0,0 +1,54 @@ +import struct + +opcodes = [ +(0, "REP_TCP_SEQ_NUM", "rep tcp seq_num", True), +(1, "REP_TCP_ACK_NUM", "rep tcp ack_num", True), +(2, "INS_TCP_OPTION", "ins tcp 20", True), +(3, "REP_TCP_FLAGS", "rep tcp flags", True), +(4, "REP_TCP_WIN_SIZE", "rep tcp win_size", True), +(5, "REP_TCP_SRC_PORT", "rep tcp src_port", True), +(6, "REP_TCP_DEST_PORT", "rep tcp dest_port", True), +(7, "REP_TCP_HEADER_LENGTH", "rep tcp tcp_hdr_len", True), +(8, "REP_IPV4_VERSION_IHL", "rep ipv4 version_ihl", True), +(9, "REP_IPV4_DSCP_ECN", "rep ipv4 dscp_esn", True), +(10, "REP_IPV4_TOT_LEN", "rep ipv4 tot_len", True), +(11, "REP_IPV4_SOURCE_ADDR", "rep ipv4 src_ip", True), +(12, "REP_IPV4_DEST_ADDR", "rep ipv4 dest_ip", True), +(13, "INS_IP_OPTION", "ins ipv4 20", True), +(14, "TRUN_TCP_HEADER", "trun tcp 0", True) +] + +def translate_instruction(instruction: str): + opcode, min_length, max_length, value = instruction.strip().split() + for i, op in enumerate(opcodes): + if op[1] == opcode: + print(f"iterating opcode {op[1]}") + opcode = op[0] + break + print(f"Value {value}") + if (op[3] == True): + value_bytes = bytes.fromhex(value[2:]) # convert hex string to bytes + else: + value = int(value, 10) + value_bytes = struct.pack('!B', value) + + script_bytes = struct.pack('!B', 0) + + min_value = int(min_length, 10) + min_value_bytes = struct.pack('!B', min_value) + + max_value = int(max_length, 10) + max_value_bytes = struct.pack('!B', max_value) + return struct.pack("!B", opcode) + script_bytes + min_value_bytes + max_value_bytes + value_bytes # concatenate opcode byte and value bytes + +def main(): + with open("fuzz_in_vuln_instructions_2.txt", "r") as f: + instructions = f.readlines() + + for instruction in instructions: + with open("/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/fuzz_in_vuln/instruction_"+str(instructions.index(instruction))+".bin", "wb") as f: + bytes_ = translate_instruction(instruction) + f.write(bytes_) + +if __name__ == "__main__": + main() diff --git a/custom_mutators/packetdrill/fuzz-udp-instructions.txt b/custom_mutators/packetdrill/fuzz-udp-instructions.txt new file mode 100644 index 0000000000..841f67c0e7 --- /dev/null +++ b/custom_mutators/packetdrill/fuzz-udp-instructions.txt @@ -0,0 +1,3 @@ +INSERT_IP_OPTION 8 24 0x0204E123 +REPLACE_IPV4_HEADER_LENGTH 5 5 0x45 +REPLACE_IPV4_SOURCE_ADDR 2 4 0x7D004B14 \ No newline at end of file diff --git a/custom_mutators/packetdrill/fuzz_in_2_instructions.txt b/custom_mutators/packetdrill/fuzz_in_2_instructions.txt new file mode 100644 index 0000000000..ab960a38de --- /dev/null +++ b/custom_mutators/packetdrill/fuzz_in_2_instructions.txt @@ -0,0 +1,34 @@ +REP_TCP_SEQ_NUM 6 8 0x0000A7E4 +REP_TCP_ACK_NUM 6 8 0x0000A7E4 +INS_TCP_OPTION 8 8 0xA4000000 +INS_TCP_OPTION 8 8 0xAE04E546 +INS_TCP_OPTION 8 8 0x0205E321 +INS_TCP_OPTION 8 8 0x0203E300 +INS_TCP_OPTION 8 8 0x03000000 +INS_TCP_OPTION 8 8 0x03020000 +INS_TCP_OPTION 8 8 0x03030700 +INS_TCP_OPTION 8 8 0x02050700 +INS_TCP_OPTION 8 8 0x040A0700 +INS_TCP_OPTION 8 8 0x04FF0700 +INS_TCP_OPTION 8 8 0x0204FFFF +INS_TCP_OPTION 8 8 0x0304FFFF +REP_TCP_FLAGS 5 5 0x24 +REP_TCP_FLAGS 5 5 0x30 +REP_TCP_FLAGS 5 5 0xFF +REP_TCP_WIN_SIZE 6 6 0xFFFF +REP_TCP_WIN_SIZE 6 6 0x0000 +REP_TCP_SRC_PORT 6 6 0xFFFF +REP_TCP_DEST_PORT 6 6 0xFFFF +REP_TCP_HEADER_LENGTH 5 5 0x60 +REP_IPV4_VERSION_IHL 5 5 0x47 +REP_IPV4_DSCP_ECN 5 5 0x00 +REP_IPV4_TOT_LEN 6 6 0xFF +REP_IPV4_SOURCE_ADDR 6 8 0xFFFFFFFF +REP_IPV4_SOURCE_ADDR 6 8 0x12F54E34 +REP_IPV4_SOURCE_ADDR 6 8 0x00000000 +REP_IPV4_DEST_ADDR 6 8 0xFFFFFFFF +REP_IPV4_DEST_ADDR 6 8 0x12F54E34 +REP_IPV4_DEST_ADDR 6 8 0x00000000 +INS_IP_OPTION 8 24 0x0204E123 +INS_IP_OPTION 8 24 0x0206E123 +TRUN_TCP_HEADER 5 5 20 \ No newline at end of file diff --git a/custom_mutators/packetdrill/fuzz_in_vuln_instructions.txt b/custom_mutators/packetdrill/fuzz_in_vuln_instructions.txt new file mode 100644 index 0000000000..5735b5ae45 --- /dev/null +++ b/custom_mutators/packetdrill/fuzz_in_vuln_instructions.txt @@ -0,0 +1,4 @@ +REP_TCP_HEADER_LENGTH 5 5 0x60 +TRUN_TCP_HEADER 5 5 15 +REP_IPV4_VERSION_IHL 5 5 0x45 +INS_TCP_OPTION 8 8 0x020402F0 \ No newline at end of file diff --git a/custom_mutators/packetdrill/fuzz_in_vuln_instructions_2.txt b/custom_mutators/packetdrill/fuzz_in_vuln_instructions_2.txt new file mode 100644 index 0000000000..7d04789028 --- /dev/null +++ b/custom_mutators/packetdrill/fuzz_in_vuln_instructions_2.txt @@ -0,0 +1 @@ +REP_IPV4_VERSION_IHL 5 5 0x45 \ No newline at end of file diff --git a/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-established-option.pkt b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-established-option.pkt new file mode 100644 index 0000000000..59be80e73d --- /dev/null +++ b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-established-option.pkt @@ -0,0 +1,10 @@ + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 + +0 bind(3, ..., ...) = 0 + +0 listen(3, 1) = 0 + +0...0.200 accept(3, ..., ...) = 4 ++.1 < S 0:0(0) win 32792 + +0 > S. 0:0(0) ack 1 ++.1 < . 1:1(0) ack 1 win 257 ++.1 < P. 1:1(0) ack 1 win 257 ++.1 < P. 1:2(1) ack 1 win 257 \ No newline at end of file diff --git a/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-established.pkt b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-established.pkt new file mode 100644 index 0000000000..9c542dd03c --- /dev/null +++ b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-established.pkt @@ -0,0 +1,10 @@ + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 + +0 bind(3, ..., ...) = 0 + +0 listen(3, 1) = 0 + +0...0.200 accept(3, ..., ...) = 4 ++.1 < S 0:0(0) win 32792 + +0 > S. 0:0(0) ack 1 ++.1 < . 1:1(0) ack 1 win 257 ++.1 < P. 1:1(0) ack 1 win 257 ++.1 < P. 1:2(1) ack 1 win 257 \ No newline at end of file diff --git a/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-fin-wait.pkt b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-fin-wait.pkt new file mode 100644 index 0000000000..b78cb640ea --- /dev/null +++ b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-fin-wait.pkt @@ -0,0 +1,13 @@ + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 + +0 bind(3, ..., ...) = 0 + +0 listen(3, 1) = 0 + +0...0.200 accept(3, ..., ...) = 4 ++.1 < S 0:0(0) win 32792 + +0 > S. 0:0(0) ack 1 ++.1 < . 1:1(0) ack 1 win 257 ++.1 < P. 1:21(20) ack 1 win 257 + +.01 close(4) = 0 + +0 > F. 1:1(0) ack 2 + +.01 < . 2:2(0) ack 2 win 257 + +.01 < . 2:2(0) ack 2 win 257 \ No newline at end of file diff --git a/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-last-ack.pkt b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-last-ack.pkt new file mode 100644 index 0000000000..86b238d536 --- /dev/null +++ b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-last-ack.pkt @@ -0,0 +1,11 @@ + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 + +0 bind(3, ..., ...) = 0 + +0 listen(3, 1) = 0 + +0...0.200 accept(3, ..., ...) = 4 ++.1 < S 0:0(0) win 32792 + +0 > S. 0:0(0) ack 1 ++.1 < . 1:1(0) ack 1 win 257 ++.1 < P. 1:21(20) ack 1 win 257 + +.01 < F. 1:1(0) ack 1 win 257 + +.01 < F. 1:1(0) ack 1 win 257 \ No newline at end of file diff --git a/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-listen.pkt b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-listen.pkt new file mode 100644 index 0000000000..04c72955ba --- /dev/null +++ b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-listen.pkt @@ -0,0 +1,5 @@ + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 + +0 bind(3, ..., ...) = 0 + +0 listen(3, 1) = 0 ++.1 < S 0:0(0) win 32792 \ No newline at end of file diff --git a/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-send.pkt b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-send.pkt new file mode 100644 index 0000000000..54615bbeff --- /dev/null +++ b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-send.pkt @@ -0,0 +1,12 @@ + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 + +0 bind(3, ..., ...) = 0 + +0 listen(3, 1) = 0 + +0...0.200 accept(3, ..., ...) = 4 ++.1 < S 0:0(0) win 32792 + +0 > S. 0:0(0) ack 1 + +.1 < . 1:1(0) ack 1 win 257 + +.1 < P. 1:21(20) ack 1 win 257 + +0 write(4, ..., 60) = 60 + +.1 < . 1:1(0) ack 10001 win 50000 + +.1 < . 1:1(0) ack 10001 win 50000 \ No newline at end of file diff --git a/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-syn-rcvd.pkt b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-syn-rcvd.pkt new file mode 100644 index 0000000000..bc7603bde8 --- /dev/null +++ b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-syn-rcvd.pkt @@ -0,0 +1,9 @@ + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 + +0 bind(3, ..., ...) = 0 + +0 listen(3, 1) = 0 + +0...0.200 accept(3, ..., ...) = 4 ++.1 < S 0:0(0) win 32792 + +0 > S. 0:0(0) ack 1 ++.1 < . 1:1(0) ack 1 win 257 ++.1 < . 1:1(0) ack 1 win 257 \ No newline at end of file diff --git a/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-syn-sent.pkt b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-syn-sent.pkt new file mode 100644 index 0000000000..49625612db --- /dev/null +++ b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-syn-sent.pkt @@ -0,0 +1,5 @@ + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 + +.1...0.200 connect(3, ..., ...) = 0 + +0 > S 0:0(0) + +.1 < S. 0:0(0) ack 1 win 5792 + +.1 < S. 0:0(0) ack 1 win 5792 diff --git a/custom_mutators/packetdrill/post_pd_fuzz.so.c b/custom_mutators/packetdrill/post_pd_fuzz.so.c new file mode 100644 index 0000000000..ee09388dc2 --- /dev/null +++ b/custom_mutators/packetdrill/post_pd_fuzz.so.c @@ -0,0 +1,77 @@ +/* + american fuzzy lop++ - postprocessor for PNG + ------------------------------------------ + + Originally written by Michal Zalewski + + Copyright 2015 Google Inc. All rights reserved. + Adapted to the new API, 2020 by Dominik Maier + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + See post_library.so.c for a general discussion of how to implement + postprocessors. This specific postprocessor attempts to fix up PNG + checksums, providing a slightly more complicated example than found + in post_library.so.c. + + Compile with: + + gcc -shared -Wall -O3 post_library_png.so.c -o post_library_png.so -lz + + */ + +#include +#include +#include +#include +#include +#include +#include "alloc-inl.h" + +#include "custom_mutator_helpers.h" + +/* A macro to round an integer up to 4 kB. */ + +#define UP4K(_i) ((((_i) >> 12) + 1) << 12) + +typedef struct my_mutator { + + afl_t *afl; + +} my_mutator_t; + +void *afl_custom_init(afl_t *afl, unsigned int seed) { + + my_mutator_t *data = calloc(1, sizeof(my_mutator_t)); + if (!data) { + + perror("afl_custom_init alloc"); + return NULL; + + } + + data->afl = afl; + + return data; + +} + +size_t afl_custom_post_process(my_mutator_t *data, const unsigned char *in_buf, + unsigned int len, + const unsigned char **out_buf) { + + +} + +/* Gets called afterwards */ +void afl_custom_deinit(post_state_t *data) { + + free(data->buf); + free(data); + +} + diff --git a/custom_mutators/packetdrill/templates/fuzz-template-tcp-established-option.pkt b/custom_mutators/packetdrill/templates/fuzz-template-tcp-established-option.pkt new file mode 100644 index 0000000000..59be80e73d --- /dev/null +++ b/custom_mutators/packetdrill/templates/fuzz-template-tcp-established-option.pkt @@ -0,0 +1,10 @@ + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 + +0 bind(3, ..., ...) = 0 + +0 listen(3, 1) = 0 + +0...0.200 accept(3, ..., ...) = 4 ++.1 < S 0:0(0) win 32792 + +0 > S. 0:0(0) ack 1 ++.1 < . 1:1(0) ack 1 win 257 ++.1 < P. 1:1(0) ack 1 win 257 ++.1 < P. 1:2(1) ack 1 win 257 \ No newline at end of file diff --git a/custom_mutators/packetdrill/templates/fuzz-template-tcp-established.pkt b/custom_mutators/packetdrill/templates/fuzz-template-tcp-established.pkt new file mode 100644 index 0000000000..9c542dd03c --- /dev/null +++ b/custom_mutators/packetdrill/templates/fuzz-template-tcp-established.pkt @@ -0,0 +1,10 @@ + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 + +0 bind(3, ..., ...) = 0 + +0 listen(3, 1) = 0 + +0...0.200 accept(3, ..., ...) = 4 ++.1 < S 0:0(0) win 32792 + +0 > S. 0:0(0) ack 1 ++.1 < . 1:1(0) ack 1 win 257 ++.1 < P. 1:1(0) ack 1 win 257 ++.1 < P. 1:2(1) ack 1 win 257 \ No newline at end of file diff --git a/custom_mutators/packetdrill/templates/fuzz-template-tcp-listen.pkt b/custom_mutators/packetdrill/templates/fuzz-template-tcp-listen.pkt new file mode 100644 index 0000000000..04c72955ba --- /dev/null +++ b/custom_mutators/packetdrill/templates/fuzz-template-tcp-listen.pkt @@ -0,0 +1,5 @@ + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 + +0 bind(3, ..., ...) = 0 + +0 listen(3, 1) = 0 ++.1 < S 0:0(0) win 32792 \ No newline at end of file diff --git a/custom_mutators/packetdrill/udp_templates/fuzz_template_socket_closed.pkt b/custom_mutators/packetdrill/udp_templates/fuzz_template_socket_closed.pkt new file mode 100644 index 0000000000..069a9cbc9c --- /dev/null +++ b/custom_mutators/packetdrill/udp_templates/fuzz_template_socket_closed.pkt @@ -0,0 +1,3 @@ + +0 < udp (1) + +0 < udp (0) + +0 < udp (30) \ No newline at end of file diff --git a/custom_mutators/packetdrill/udp_templates/fuzz_template_socket_open.pkt b/custom_mutators/packetdrill/udp_templates/fuzz_template_socket_open.pkt new file mode 100644 index 0000000000..3c527177a9 --- /dev/null +++ b/custom_mutators/packetdrill/udp_templates/fuzz_template_socket_open.pkt @@ -0,0 +1,7 @@ + 0 socket(..., SOCK_DGRAM, IPPROTO_UDP) = 3 + +0 bind(3, ..., ...) = 0 + +0 sendto(3, ..., 20, MSG_CONFIRM, ..., ...) = 20 + +0 > udp (20) + +0 < udp (1) + +0 < udp (0) + +0 < udp (30) \ No newline at end of file diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 23c20cc43b..5ea5da6511 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -718,6 +718,9 @@ typedef struct afl_state { u8 *testcase_buf, *splicecase_buf; + /* Needed when we want to start mutations at a certain offset */ + u8 out_buf_offset; + u32 custom_mutators_count; struct custom_mutator *current_custom_fuzz; @@ -759,6 +762,14 @@ typedef struct afl_state { * is too large) */ struct queue_entry **q_testcase_cache; + /* Pointer to file object used for communicating with post-processor */ + u8 *file_in; + u8 *file_out; + u8 *mmap_in; + u8 *mmap_out; + char *seed_file; + char *pd_script_file; + #ifdef INTROSPECTION char mutation[8072]; char m_tmp[4096]; diff --git a/include/config.h b/include/config.h index 21701515db..f9548a835e 100644 --- a/include/config.h +++ b/include/config.h @@ -109,7 +109,7 @@ Config can be adjusted via AFL_STATSD_HOST and AFL_STATSD_PORT environment variable. */ -#define STATSD_UPDATE_SEC 1 +#define STATSD_UPDATE_SEC 120 #define STATSD_DEFAULT_PORT 8125 #define STATSD_DEFAULT_HOST "127.0.0.1" diff --git a/include/forkserver.h b/include/forkserver.h index 59ce0ee7bb..fc9276e74a 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -85,7 +85,10 @@ typedef struct afl_forkserver { s32 fsrv_pid, /* PID of the fork server */ child_pid, /* PID of the fuzzed program */ + pd_pid, /* PID of PacketDrill */ + pd_tap_fd, /* TAP fd used by PacketDrill */ child_status, /* waitpid result for the child */ + timeout_pending, /* We set this whenever we start a timeout and need to kill the child at the timeout's expiration */ out_dir_fd; /* FD of the lock file */ s32 out_fd, /* Persistent fd for fsrv->out_file */ @@ -203,6 +206,9 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, void afl_fsrv_killall(void); void afl_fsrv_deinit(afl_forkserver_t *fsrv); void afl_fsrv_kill(afl_forkserver_t *fsrv); +void handle_timeout(); + + #ifdef __APPLE__ #define MSG_FORK_ON_APPLE \ diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 194d49b0b4..3f44977268 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1204,6 +1204,8 @@ static void __afl_start_forkserver(void) { } + // AFL forkserver waits at this point for an execution to complete + if (waitpid(child_pid, &status, is_persistent ? WUNTRACED : 0) < 0) { write_error("waitpid"); diff --git a/qemu_mode/qemuafl b/qemu_mode/qemuafl index dc19175a0b..b40e6e8dc6 160000 --- a/qemu_mode/qemuafl +++ b/qemu_mode/qemuafl @@ -1 +1 @@ -Subproject commit dc19175a0bf4cf34e19944d084d92f33f26df93d +Subproject commit b40e6e8dc680a0e633484f94bb30ab3d12e46656 diff --git a/src/afl-cc.c b/src/afl-cc.c index 53fba1e7b3..98d5f229b1 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1097,7 +1097,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { cc_params[cc_par_cnt++] = "-D__AFL_FUZZ_INIT()=" - "int __afl_sharedmem_fuzzing = 1;" + "int __afl_sharedmem_fuzzing = 0;" "extern unsigned int *__afl_fuzz_len;" "extern unsigned char *__afl_fuzz_ptr;" "unsigned char __afl_fuzz_alt[1048576];" diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 628ff590e7..364e4c84dc 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -48,6 +48,16 @@ #include #include #include +#include +#include +#include +#include +#include + +#define TAP 1 +#define TUN 2 + +#define CONFIG_NET_INTERFACE TAP /** * The correct fds for reading and writing pipes @@ -71,7 +81,7 @@ static void fsrv_exec_child(afl_forkserver_t *fsrv, char **argv) { } -/* Initializes the struct */ +/* Initializes the fsrv struct */ void afl_fsrv_init(afl_forkserver_t *fsrv) { @@ -374,6 +384,62 @@ static void report_error_and_exit(int error) { } + +/* This function creates a TAP interface and returns the file descriptor +* The TAP interface is used by PacketDrill to send packets to the target under test */ +int tun_alloc(char *dev, int flags) { + + struct ifreq ifr; + int fd, err; + char *clonedev = "/dev/net/tun"; + + /* Arguments taken by the function: + * + * char *dev: the name of an interface (or '\0'). MUST have enough + * space to hold the interface name if '\0' is passed + * int flags: interface flags (eg, IFF_TUN etc.) + */ + + /* open the clone device */ + if( (fd = open(clonedev, O_RDWR)) < 0 ) { + printf("tun open failed with code %d and errno %d...\n", fd, errno); + return fd; + } + + printf("Tap file descriptor is %d...\n", fd); + + /* preparation of the struct ifr, of type "struct ifreq" */ + memset(&ifr, 0, sizeof(ifr)); + + ifr.ifr_flags = flags; /* IFF_TUN or IFF_TAP, plus maybe IFF_NO_PI */ + + if (*dev) { + /* if a device name was specified, put it in the structure; otherwise, + * the kernel will try to allocate the "next" device of the + * specified type */ + strncpy(ifr.ifr_name, dev, IFNAMSIZ); + } + + /* try to create the device */ + if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) { + printf("tun ioctl failed with code %d and errno %s...\n", err, strerror(errno)); + close(fd); + return err; + } + + /* if the operation was successful, write back the name of the + * interface to the variable "dev", so the caller can know + * it. Note that the caller MUST reserve space in *dev (see calling + * code below) */ + strcpy(dev, ifr.ifr_name); + + /* this is the special file descriptor that the caller will use to talk + * with the virtual interface */ + return fd; +} + + + /* Spins up fork server. The idea is explained here: https://lcamtuf.blogspot.com/2014/10/fuzzing-binaries-without-execve.html @@ -753,6 +819,22 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, "print_suppressions=0", 1); + + /* Setup environment variable for child */ + // if (getenv("TAP_INTERFACE_NAME")) { + // const char *interface_name = getenv("TAP_INTERFACE_NAME"); + + // setenv + // } + + int res = setenv("ASAN_SYMBOLIZER_PATH", "/usr/bin/llvm-symbolizer-12", 1); + + if (res != 0) { + printf("Setting ASAN_SYMBOLIZER_PATH failed with errno %d...\n", errno); + } else { + printf("Set ASAN_SYMBOLIZER_PATH successfully...\n"); + } + fsrv->init_child_func(fsrv, argv); /* Use a distinctive bitmap signature to tell the parent about execv() @@ -1027,6 +1109,32 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } + if (getenv("PD_ENABLE_TAP")) { + // Now we start our TAP interface and save the fd + const char *interface_name = getenv("TAP_INTERFACE_NAME"); + + if (interface_name == NULL || strlen(interface_name) >= IFNAMSIZ) { + interface_name = CONFIG_NET_INTERFACE == TAP ? "tap1" : "tun0"; + } + + char tun_name[strlen(interface_name) + 1]; + + /* Connect to the device */ + strncpy(tun_name, interface_name, strlen(interface_name)); + tun_name[strlen(interface_name)] = '\0'; + + int interface_flag = CONFIG_NET_INTERFACE == TAP ? IFF_TAP : IFF_TUN; + int tun_fd = tun_alloc(tun_name, interface_flag | IFF_NO_PI); /* tun interface */ + + if(tun_fd < 0){ + printf("Allocating interface failed with code: %d and errno: %d...\n", tun_fd, errno); + exit(-1); + } else { + printf("Allocating tap interface %s succeeded with fd %d\n", tun_name, tun_fd); + fsrv->pd_tap_fd = tun_fd; + } + } + return; } @@ -1267,6 +1375,53 @@ void afl_fsrv_kill(afl_forkserver_t *fsrv) { } +void handle_timeout_fsrv(afl_forkserver_t *fsrv) { + + printf("Timeout called in forkserver...\n"); + + if (fsrv->timeout_pending && fsrv->child_pid) { + /* If there was no response from forkserver after timeout seconds, + we kill the child. The forkserver should inform us afterwards */ + + printf("Timeout handled in signal handler with %d...\n", fsrv->kill_signal); + s32 tmp_pid = fsrv->child_pid; + if (tmp_pid > 0) { + + int kill_success = kill(tmp_pid, fsrv->kill_signal); + if (kill_success < 0) { + printf("Error killing pd_pid with errno %d...\n", errno); + } + fsrv->child_pid = -1; + + } + + s32 pd_pid = fsrv->pd_pid; + + if (pd_pid > 0) { + int kill_success = kill(pd_pid, fsrv->kill_signal); + if (kill_success < 0) { + printf("Error killing pd_pid with errno %d...\n", errno); + } + fsrv->pd_pid = -1; + } + + fsrv->timeout_pending = 0; + fsrv->last_run_timed_out = 1; + } +} + + +void handle_timeout() { + + printf("handle_timeout...\n"); + + LIST_FOREACH(&fsrv_list, afl_forkserver_t, { + + handle_timeout_fsrv(el); + + }); +} + /* Get the map size from the target forkserver */ u32 afl_fsrv_get_mapsize(afl_forkserver_t *fsrv, char **argv, @@ -1403,7 +1558,7 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, volatile u8 *stop_soon_p) { s32 res; - u32 exec_ms; + u32 exec_ms = 0; u32 write_value = fsrv->last_run_timed_out; #ifdef __linux__ @@ -1534,13 +1689,134 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, } - exec_ms = read_s32_timed(fsrv->fsrv_st_fd, &fsrv->child_status, timeout, - stop_soon_p); + struct itimerval it; - if (exec_ms > timeout) { + //printf("timeout is %d...\n", timeout); - /* If there was no response from forkserver after timeout seconds, - we kill the child. The forkserver should inform us afterwards */ + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 0; + + it.it_value.tv_sec = (timeout / 1000); + it.it_value.tv_usec = (timeout % 1000) * 1000; + + int timerRes = setitimer(ITIMER_REAL, &it, NULL); + + // printf("it.it_value.tv_usec is %ld...\n", it.it_value.tv_usec); + + if (timerRes == 0) { + //printf("Timer result is %d...\n", timerRes); + } else { + //printf("Timer result is %d and errno %d...\n", timerRes, errno); + } + + + fsrv->timeout_pending = 1; + + // Confirm TAP interface has been allocated + if (getenv("PD_ENABLE_TAP") && fsrv->pd_tap_fd < 0) { + printf("TAP interface not found...\n"); + exit(-1); + } + + // TODO: Invoking fork should be done only under specific circumstance. + // TODO: We want to kill pd_pid if it times out + pid_t pd_pid = fork(); + if (pd_pid==0) { /* child process */ + + /* open /dev/null for writing */ + int fd = open("/dev/null", O_WRONLY); + + dup2(fd, 1); /* make stdout a copy of fd (> /dev/null) */ + dup2(fd, 2); /* ...and same with stderr */ + close(fd); /* close fd */ + + /* stdout and stderr now write to /dev/null */ + /* ready to call exec */ + + const char *pd_script = fsrv->out_file; + + char *argv[]={"/home/pamusuo/research/ampaschal-packetdrill/gtests/net/packetdrill/packetdrill", + "--so_filename=/home/pamusuo/research/rtos-fuzzing/rtos-bridge/libfreertos-bridge.so", + "--fm_filename=/home/pamusuo/research/rtos-fuzzing/packet-mutation/libmutation-interface.so", + "--local_ip=125.0.75.0", + "--remote_ip=125.0.75.20", + "--connect_port=8765", + "--bind_port=5678", + "--is_anyip", + "--non_fatal=packet", + "--tolerance_usecs=1000000", pd_script, NULL}; + + // char *argv[]={"/home/pamusuo/research/ampaschal-packetdrill/gtests/net/packetdrill/packetdrill", + // "--so_filename=/home/pamusuo/research/rtos-fuzzing/rtos-bridge/libfreertos-bridge.so", + // "--fm_filename=/home/pamusuo/research/rtos-fuzzing/packet-mutation/libmutation-interface.so", + // "--local_ip=fd00::302:304:506:708", + // "--bind_port=5678", + // "--connect_port=8765", + // "--ip_version=ipv6", + // "--is_anyip", + // "--non_fatal=packet", + // "--tolerance_usecs=1000000", pd_script, NULL}; + + if (fsrv->pd_tap_fd > 0) { + printf("Using env variables to invoke packetdrill...\n"); + //char *env[] = {"PD_TAP_FD=" + fsrv->pd_tap_fd, NULL}; + char fd_ptr[3]; + sprintf(fd_ptr, "%d", fsrv->pd_tap_fd); + setenv("PD_TAP_FD", fd_ptr, 1); + res = execv("/home/pamusuo/research/ampaschal-packetdrill/gtests/net/packetdrill/packetdrill", argv); + } else { + printf("Not using env variables to invoke pd...\n"); + res = execv("/home/pamusuo/research/ampaschal-packetdrill/gtests/net/packetdrill/packetdrill", argv); + } + + if (res != 0) { + printf("An error occurred executing with errno %d\n", errno); + } + exit(127); /* only if execv fails */ + } + + fsrv->pd_pid = pd_pid; + + restart_read: + res = read(fsrv->fsrv_st_fd, &fsrv->child_status, 4); + + //printf("Child has returned with status %d...\n", fsrv->child_status); + + if (likely(res == 4)) { // for speed we put this first + + getitimer(ITIMER_REAL, &it); + exec_ms = (u64) timeout - (it.it_value.tv_sec * 1000 + + it.it_value.tv_usec / 1000); + + + } else if (unlikely(res == -1 && errno == EINTR)) { + + goto restart_read; + + } else if (unlikely(res < 4)) { + + exec_ms = 0; + + } + + /* We disarm the timer at this point */ + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 0; + + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 0; + + setitimer(ITIMER_REAL, &it, NULL); + fsrv->timeout_pending = 0; + + + /* exec_ms = read_s32_timed(fsrv->fsrv_st_fd, &fsrv->child_status, timeout, + stop_soon_p); */ + + /*if (exec_ms > timeout) { + + If there was no response from forkserver after timeout seconds, + we kill the child. The forkserver should inform us afterwards s32 tmp_pid = fsrv->child_pid; if (tmp_pid > 0) { @@ -1553,7 +1829,7 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, fsrv->last_run_timed_out = 1; if (read(fsrv->fsrv_st_fd, &fsrv->child_status, 4) < 4) { exec_ms = 0; } - } + } */ if (!exec_ms) { diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index e41d29fda2..7a1b138e91 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -26,6 +26,7 @@ #include "afl-fuzz.h" #include #include "cmplog.h" +#include "forkserver.h" #ifdef HAVE_AFFINITY @@ -2554,6 +2555,18 @@ static void handle_skipreq(int sig) { } + + +/* Handle timeout (SIGALRM). */ + +static void handle_timeout_signal(int sig) { + + (void)sig; + printf("handle_timeout_signal"); + handle_timeout(); + +} + /* Setup shared map for fuzzing with input via sharedmem */ void setup_testcase_shmem(afl_state_t *afl) { @@ -2914,6 +2927,11 @@ void setup_signal_handlers(void) { sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); + /* Exec timeout notifications. */ + + sa.sa_handler = handle_timeout_signal; + sigaction(SIGALRM, &sa, NULL); + /* Window resize */ sa.sa_handler = handle_resize; diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index ed9e7a81db..35916f0afa 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -458,6 +458,11 @@ u8 fuzz_one_original(afl_state_t *afl) { orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur); len = afl->queue_cur->len; + if (len < 5) { + // Each seed should contain 4 meta data bytes + return 1; + } + out_buf = afl_realloc(AFL_BUF_PARAM(out), len); if (unlikely(!out_buf)) { PFATAL("alloc"); } @@ -535,6 +540,14 @@ u8 fuzz_one_original(afl_state_t *afl) { memcpy(out_buf, in_buf, len); + + // Bias fuzzing on data segment of operand + + out_buf += 4; + afl->out_buf_offset = 4; + len = len - 4; + + /********************* * PERFORMANCE SCORE * *********************/ @@ -965,47 +978,6 @@ u8 fuzz_one_original(afl_state_t *afl) { if (len < 4) { goto skip_bitflip; } - /* Four walking bytes. */ - - afl->stage_name = "bitflip 32/8"; - afl->stage_short = "flip32"; - afl->stage_cur = 0; - afl->stage_max = len - 3; - - orig_hit_cnt = new_hit_cnt; - - for (i = 0; i < len - 3; ++i) { - - /* Let's consult the effector map... */ - if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)] && - !eff_map[EFF_APOS(i + 2)] && !eff_map[EFF_APOS(i + 3)]) { - - --afl->stage_max; - continue; - - } - - afl->stage_cur_byte = i; - - *(u32 *)(out_buf + i) ^= 0xFFFFFFFF; - -#ifdef INTROSPECTION - snprintf(afl->mutation, sizeof(afl->mutation), "%s FLIP_BIT32-%u", - afl->queue_cur->fname, afl->stage_cur); -#endif - - if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } - ++afl->stage_cur; - - *(u32 *)(out_buf + i) ^= 0xFFFFFFFF; - - } - - new_hit_cnt = afl->queued_items + afl->saved_crashes; - - afl->stage_finds[STAGE_FLIP32] += new_hit_cnt - orig_hit_cnt; - afl->stage_cycles[STAGE_FLIP32] += afl->stage_max; - skip_bitflip: if (afl->no_arith) { goto skip_arith; } @@ -1098,126 +1070,62 @@ u8 fuzz_one_original(afl_state_t *afl) { afl->stage_finds[STAGE_ARITH8] += new_hit_cnt - orig_hit_cnt; afl->stage_cycles[STAGE_ARITH8] += afl->stage_max; - /* 16-bit arithmetics, both endians. */ +skip_arith: - if (len < 2) { goto skip_arith; } + /********************** + * INTERESTING VALUES * + **********************/ - afl->stage_name = "arith 16/8"; - afl->stage_short = "arith16"; + afl->stage_name = "interest 8/8"; + afl->stage_short = "int8"; afl->stage_cur = 0; - afl->stage_max = 4 * (len - 1) * ARITH_MAX; + afl->stage_max = len * sizeof(interesting_8); + + afl->stage_val_type = STAGE_VAL_LE; orig_hit_cnt = new_hit_cnt; - for (i = 0; i < (u32)len - 1; ++i) { + /* Setting 8-bit integers. */ - u16 orig = *(u16 *)(out_buf + i); + for (i = 0; i < (u32)len; ++i) { + + u8 orig = out_buf[i]; /* Let's consult the effector map... */ - if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)]) { + if (!eff_map[EFF_APOS(i)]) { - afl->stage_max -= 4 * ARITH_MAX; + afl->stage_max -= sizeof(interesting_8); continue; } afl->stage_cur_byte = i; - for (j = 1; j <= ARITH_MAX; ++j) { - - u16 r1 = orig ^ (orig + j), r2 = orig ^ (orig - j), - r3 = orig ^ SWAP16(SWAP16(orig) + j), - r4 = orig ^ SWAP16(SWAP16(orig) - j); - - /* Try little endian addition and subtraction first. Do it only - if the operation would affect more than one byte (hence the - & 0xff overflow checks) and if it couldn't be a product of - a bitflip. */ - - afl->stage_val_type = STAGE_VAL_LE; - - if ((orig & 0xff) + j > 0xff && !could_be_bitflip(r1)) { - - afl->stage_cur_val = j; - *(u16 *)(out_buf + i) = orig + j; - -#ifdef INTROSPECTION - snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH16+-%u-%u", - afl->queue_cur->fname, i, j); -#endif - - if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } - ++afl->stage_cur; - - } else { - - --afl->stage_max; - - } - - if ((orig & 0xff) < j && !could_be_bitflip(r2)) { - - afl->stage_cur_val = -j; - *(u16 *)(out_buf + i) = orig - j; - -#ifdef INTROSPECTION - snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH16--%u-%u", - afl->queue_cur->fname, i, j); -#endif - - if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } - ++afl->stage_cur; - - } else { - - --afl->stage_max; - - } - - /* Big endian comes next. Same deal. */ - - afl->stage_val_type = STAGE_VAL_BE; - - if ((orig >> 8) + j > 0xff && !could_be_bitflip(r3)) { - - afl->stage_cur_val = j; - *(u16 *)(out_buf + i) = SWAP16(SWAP16(orig) + j); - -#ifdef INTROSPECTION - snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH16+BE-%u-%u", - afl->queue_cur->fname, i, j); -#endif + for (j = 0; j < (u32)sizeof(interesting_8); ++j) { - if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } - ++afl->stage_cur; + /* Skip if the value could be a product of bitflips or arithmetics. */ - } else { + if (could_be_bitflip(orig ^ (u8)interesting_8[j]) || + could_be_arith(orig, (u8)interesting_8[j], 1)) { --afl->stage_max; + continue; } - if ((orig >> 8) < j && !could_be_bitflip(r4)) { - - afl->stage_cur_val = -j; - *(u16 *)(out_buf + i) = SWAP16(SWAP16(orig) - j); + afl->stage_cur_val = interesting_8[j]; + out_buf[i] = interesting_8[j]; #ifdef INTROSPECTION - snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH16_BE-%u-%u", - afl->queue_cur->fname, i, j); + snprintf(afl->mutation, sizeof(afl->mutation), "%s INTERESTING8_%u_%u", + afl->queue_cur->fname, i, j); #endif - if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } - ++afl->stage_cur; - - } else { - - --afl->stage_max; - - } + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } - *(u16 *)(out_buf + i) = orig; + out_buf[i] = orig; + ++afl->stage_cur; } @@ -1225,54 +1133,52 @@ u8 fuzz_one_original(afl_state_t *afl) { new_hit_cnt = afl->queued_items + afl->saved_crashes; - afl->stage_finds[STAGE_ARITH16] += new_hit_cnt - orig_hit_cnt; - afl->stage_cycles[STAGE_ARITH16] += afl->stage_max; + afl->stage_finds[STAGE_INTEREST8] += new_hit_cnt - orig_hit_cnt; + afl->stage_cycles[STAGE_INTEREST8] += afl->stage_max; - /* 32-bit arithmetics, both endians. */ + /* Setting 16-bit integers, both endians. */ - if (len < 4) { goto skip_arith; } + if (afl->no_arith || len < 2) { goto skip_interest; } - afl->stage_name = "arith 32/8"; - afl->stage_short = "arith32"; + afl->stage_name = "interest 16/8"; + afl->stage_short = "int16"; afl->stage_cur = 0; - afl->stage_max = 4 * (len - 3) * ARITH_MAX; + afl->stage_max = 2 * (len - 1) * (sizeof(interesting_16) >> 1); orig_hit_cnt = new_hit_cnt; - for (i = 0; i < (u32)len - 3; ++i) { + for (i = 0; i < len - 1; ++i) { - u32 orig = *(u32 *)(out_buf + i); + u16 orig = *(u16 *)(out_buf + i); /* Let's consult the effector map... */ - if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)] && - !eff_map[EFF_APOS(i + 2)] && !eff_map[EFF_APOS(i + 3)]) { + if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)]) { - afl->stage_max -= 4 * ARITH_MAX; + afl->stage_max -= sizeof(interesting_16); continue; } afl->stage_cur_byte = i; - for (j = 1; j <= ARITH_MAX; ++j) { + for (j = 0; j < sizeof(interesting_16) / 2; ++j) { - u32 r1 = orig ^ (orig + j), r2 = orig ^ (orig - j), - r3 = orig ^ SWAP32(SWAP32(orig) + j), - r4 = orig ^ SWAP32(SWAP32(orig) - j); + afl->stage_cur_val = interesting_16[j]; - /* Little endian first. Same deal as with 16-bit: we only want to - try if the operation would have effect on more than two bytes. */ + /* Skip if this could be a product of a bitflip, arithmetics, + or single-byte interesting value insertion. */ - afl->stage_val_type = STAGE_VAL_LE; + if (!could_be_bitflip(orig ^ (u16)interesting_16[j]) && + !could_be_arith(orig, (u16)interesting_16[j], 2) && + !could_be_interest(orig, (u16)interesting_16[j], 2, 0)) { - if ((orig & 0xffff) + j > 0xffff && !could_be_bitflip(r1)) { + afl->stage_val_type = STAGE_VAL_LE; - afl->stage_cur_val = j; - *(u32 *)(out_buf + i) = orig + j; + *(u16 *)(out_buf + i) = interesting_16[j]; #ifdef INTROSPECTION - snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH32+-%u-%u", + snprintf(afl->mutation, sizeof(afl->mutation), "%s INTERESTING16_%u_%u", afl->queue_cur->fname, i, j); #endif @@ -1285,16 +1191,19 @@ u8 fuzz_one_original(afl_state_t *afl) { } - if ((orig & 0xffff) < (u32)j && !could_be_bitflip(r2)) { + if ((u16)interesting_16[j] != SWAP16(interesting_16[j]) && + !could_be_bitflip(orig ^ SWAP16(interesting_16[j])) && + !could_be_arith(orig, SWAP16(interesting_16[j]), 2) && + !could_be_interest(orig, SWAP16(interesting_16[j]), 2, 1)) { - afl->stage_cur_val = -j; - *(u32 *)(out_buf + i) = orig - j; + afl->stage_val_type = STAGE_VAL_BE; #ifdef INTROSPECTION - snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH32_-%u-%u", - afl->queue_cur->fname, i, j); + snprintf(afl->mutation, sizeof(afl->mutation), + "%s INTERESTING16BE_%u_%u", afl->queue_cur->fname, i, j); #endif + *(u16 *)(out_buf + i) = SWAP16(interesting_16[j]); if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } ++afl->stage_cur; @@ -1304,471 +1213,76 @@ u8 fuzz_one_original(afl_state_t *afl) { } - /* Big endian next. */ + } - afl->stage_val_type = STAGE_VAL_BE; + *(u16 *)(out_buf + i) = orig; - if ((SWAP32(orig) & 0xffff) + j > 0xffff && !could_be_bitflip(r3)) { + } - afl->stage_cur_val = j; - *(u32 *)(out_buf + i) = SWAP32(SWAP32(orig) + j); + new_hit_cnt = afl->queued_items + afl->saved_crashes; -#ifdef INTROSPECTION - snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH32+BE-%u-%u", - afl->queue_cur->fname, i, j); -#endif + afl->stage_finds[STAGE_INTEREST16] += new_hit_cnt - orig_hit_cnt; + afl->stage_cycles[STAGE_INTEREST16] += afl->stage_max; - if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } - ++afl->stage_cur; + if (len < 4) { goto skip_interest; } - } else { - --afl->stage_max; - } +skip_interest: - if ((SWAP32(orig) & 0xffff) < (u32)j && !could_be_bitflip(r4)) { + /******************** + * DICTIONARY STUFF * + ********************/ - afl->stage_cur_val = -j; - *(u32 *)(out_buf + i) = SWAP32(SWAP32(orig) - j); + if (!afl->extras_cnt) { goto skip_user_extras; } -#ifdef INTROSPECTION - snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH32_BE-%u-%u", - afl->queue_cur->fname, i, j); -#endif + /* Overwrite with user-supplied extras. */ - if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } - ++afl->stage_cur; + afl->stage_name = "user extras (over)"; + afl->stage_short = "ext_UO"; + afl->stage_cur = 0; + afl->stage_max = afl->extras_cnt * len; - } else { + afl->stage_val_type = STAGE_VAL_NONE; - --afl->stage_max; + orig_hit_cnt = new_hit_cnt; - } - - *(u32 *)(out_buf + i) = orig; - - } - - } - - new_hit_cnt = afl->queued_items + afl->saved_crashes; - - afl->stage_finds[STAGE_ARITH32] += new_hit_cnt - orig_hit_cnt; - afl->stage_cycles[STAGE_ARITH32] += afl->stage_max; - -skip_arith: - - /********************** - * INTERESTING VALUES * - **********************/ - - afl->stage_name = "interest 8/8"; - afl->stage_short = "int8"; - afl->stage_cur = 0; - afl->stage_max = len * sizeof(interesting_8); - - afl->stage_val_type = STAGE_VAL_LE; - - orig_hit_cnt = new_hit_cnt; - - /* Setting 8-bit integers. */ - - for (i = 0; i < (u32)len; ++i) { - - u8 orig = out_buf[i]; - - /* Let's consult the effector map... */ - - if (!eff_map[EFF_APOS(i)]) { - - afl->stage_max -= sizeof(interesting_8); - continue; - - } - - afl->stage_cur_byte = i; - - for (j = 0; j < (u32)sizeof(interesting_8); ++j) { - - /* Skip if the value could be a product of bitflips or arithmetics. */ - - if (could_be_bitflip(orig ^ (u8)interesting_8[j]) || - could_be_arith(orig, (u8)interesting_8[j], 1)) { - - --afl->stage_max; - continue; - - } - - afl->stage_cur_val = interesting_8[j]; - out_buf[i] = interesting_8[j]; - -#ifdef INTROSPECTION - snprintf(afl->mutation, sizeof(afl->mutation), "%s INTERESTING8_%u_%u", - afl->queue_cur->fname, i, j); -#endif - - if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } - - out_buf[i] = orig; - ++afl->stage_cur; - - } - - } - - new_hit_cnt = afl->queued_items + afl->saved_crashes; - - afl->stage_finds[STAGE_INTEREST8] += new_hit_cnt - orig_hit_cnt; - afl->stage_cycles[STAGE_INTEREST8] += afl->stage_max; - - /* Setting 16-bit integers, both endians. */ - - if (afl->no_arith || len < 2) { goto skip_interest; } - - afl->stage_name = "interest 16/8"; - afl->stage_short = "int16"; - afl->stage_cur = 0; - afl->stage_max = 2 * (len - 1) * (sizeof(interesting_16) >> 1); - - orig_hit_cnt = new_hit_cnt; - - for (i = 0; i < len - 1; ++i) { - - u16 orig = *(u16 *)(out_buf + i); - - /* Let's consult the effector map... */ - - if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)]) { - - afl->stage_max -= sizeof(interesting_16); - continue; - - } - - afl->stage_cur_byte = i; - - for (j = 0; j < sizeof(interesting_16) / 2; ++j) { - - afl->stage_cur_val = interesting_16[j]; - - /* Skip if this could be a product of a bitflip, arithmetics, - or single-byte interesting value insertion. */ - - if (!could_be_bitflip(orig ^ (u16)interesting_16[j]) && - !could_be_arith(orig, (u16)interesting_16[j], 2) && - !could_be_interest(orig, (u16)interesting_16[j], 2, 0)) { - - afl->stage_val_type = STAGE_VAL_LE; - - *(u16 *)(out_buf + i) = interesting_16[j]; - -#ifdef INTROSPECTION - snprintf(afl->mutation, sizeof(afl->mutation), "%s INTERESTING16_%u_%u", - afl->queue_cur->fname, i, j); -#endif - - if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } - ++afl->stage_cur; - - } else { - - --afl->stage_max; - - } - - if ((u16)interesting_16[j] != SWAP16(interesting_16[j]) && - !could_be_bitflip(orig ^ SWAP16(interesting_16[j])) && - !could_be_arith(orig, SWAP16(interesting_16[j]), 2) && - !could_be_interest(orig, SWAP16(interesting_16[j]), 2, 1)) { - - afl->stage_val_type = STAGE_VAL_BE; - -#ifdef INTROSPECTION - snprintf(afl->mutation, sizeof(afl->mutation), - "%s INTERESTING16BE_%u_%u", afl->queue_cur->fname, i, j); -#endif - - *(u16 *)(out_buf + i) = SWAP16(interesting_16[j]); - if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } - ++afl->stage_cur; - - } else { - - --afl->stage_max; - - } - - } - - *(u16 *)(out_buf + i) = orig; - - } - - new_hit_cnt = afl->queued_items + afl->saved_crashes; - - afl->stage_finds[STAGE_INTEREST16] += new_hit_cnt - orig_hit_cnt; - afl->stage_cycles[STAGE_INTEREST16] += afl->stage_max; - - if (len < 4) { goto skip_interest; } - - /* Setting 32-bit integers, both endians. */ - - afl->stage_name = "interest 32/8"; - afl->stage_short = "int32"; - afl->stage_cur = 0; - afl->stage_max = 2 * (len - 3) * (sizeof(interesting_32) >> 2); - - orig_hit_cnt = new_hit_cnt; - - for (i = 0; i < len - 3; i++) { - - u32 orig = *(u32 *)(out_buf + i); - - /* Let's consult the effector map... */ - - if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)] && - !eff_map[EFF_APOS(i + 2)] && !eff_map[EFF_APOS(i + 3)]) { - - afl->stage_max -= sizeof(interesting_32) >> 1; - continue; - - } - - afl->stage_cur_byte = i; - - for (j = 0; j < sizeof(interesting_32) / 4; ++j) { - - afl->stage_cur_val = interesting_32[j]; - - /* Skip if this could be a product of a bitflip, arithmetics, - or word interesting value insertion. */ - - if (!could_be_bitflip(orig ^ (u32)interesting_32[j]) && - !could_be_arith(orig, interesting_32[j], 4) && - !could_be_interest(orig, interesting_32[j], 4, 0)) { - - afl->stage_val_type = STAGE_VAL_LE; - - *(u32 *)(out_buf + i) = interesting_32[j]; - -#ifdef INTROSPECTION - snprintf(afl->mutation, sizeof(afl->mutation), "%s INTERESTING32_%u_%u", - afl->queue_cur->fname, i, j); -#endif - - if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } - ++afl->stage_cur; - - } else { - - --afl->stage_max; - - } - - if ((u32)interesting_32[j] != SWAP32(interesting_32[j]) && - !could_be_bitflip(orig ^ SWAP32(interesting_32[j])) && - !could_be_arith(orig, SWAP32(interesting_32[j]), 4) && - !could_be_interest(orig, SWAP32(interesting_32[j]), 4, 1)) { - - afl->stage_val_type = STAGE_VAL_BE; - -#ifdef INTROSPECTION - snprintf(afl->mutation, sizeof(afl->mutation), - "%s INTERESTING32BE_%u_%u", afl->queue_cur->fname, i, j); -#endif - - *(u32 *)(out_buf + i) = SWAP32(interesting_32[j]); - if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } - ++afl->stage_cur; - - } else { - - --afl->stage_max; - - } - - } - - *(u32 *)(out_buf + i) = orig; - - } - - new_hit_cnt = afl->queued_items + afl->saved_crashes; - - afl->stage_finds[STAGE_INTEREST32] += new_hit_cnt - orig_hit_cnt; - afl->stage_cycles[STAGE_INTEREST32] += afl->stage_max; - -skip_interest: - - /******************** - * DICTIONARY STUFF * - ********************/ - - if (!afl->extras_cnt) { goto skip_user_extras; } - - /* Overwrite with user-supplied extras. */ - - afl->stage_name = "user extras (over)"; - afl->stage_short = "ext_UO"; - afl->stage_cur = 0; - afl->stage_max = afl->extras_cnt * len; - - afl->stage_val_type = STAGE_VAL_NONE; - - orig_hit_cnt = new_hit_cnt; - - for (i = 0; i < (u32)len; ++i) { - - u32 last_len = 0; - - afl->stage_cur_byte = i; - - /* Extras are sorted by size, from smallest to largest. This means - that we don't have to worry about restoring the buffer in - between writes at a particular offset determined by the outer - loop. */ - - for (j = 0; j < afl->extras_cnt; ++j) { - - /* Skip extras probabilistically if afl->extras_cnt > AFL_MAX_DET_EXTRAS. - Also skip them if there's no room to insert the payload, if the token - is redundant, or if its entire span has no bytes set in the effector - map. */ - - if ((afl->extras_cnt > afl->max_det_extras && - rand_below(afl, afl->extras_cnt) >= afl->max_det_extras) || - afl->extras[j].len > len - i || - !memcmp(afl->extras[j].data, out_buf + i, afl->extras[j].len) || - !memchr(eff_map + EFF_APOS(i), 1, - EFF_SPAN_ALEN(i, afl->extras[j].len))) { - - --afl->stage_max; - continue; - - } - - last_len = afl->extras[j].len; - memcpy(out_buf + i, afl->extras[j].data, last_len); - -#ifdef INTROSPECTION - snprintf(afl->mutation, sizeof(afl->mutation), - "%s EXTRAS_overwrite-%u-%u", afl->queue_cur->fname, i, j); -#endif - - if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } - - ++afl->stage_cur; - - } - - /* Restore all the clobbered memory. */ - memcpy(out_buf + i, in_buf + i, last_len); - - } - - new_hit_cnt = afl->queued_items + afl->saved_crashes; - - afl->stage_finds[STAGE_EXTRAS_UO] += new_hit_cnt - orig_hit_cnt; - afl->stage_cycles[STAGE_EXTRAS_UO] += afl->stage_max; - - /* Insertion of user-supplied extras. */ - - afl->stage_name = "user extras (insert)"; - afl->stage_short = "ext_UI"; - afl->stage_cur = 0; - afl->stage_max = afl->extras_cnt * (len + 1); - - orig_hit_cnt = new_hit_cnt; - - ex_tmp = afl_realloc(AFL_BUF_PARAM(ex), len + MAX_DICT_FILE); - if (unlikely(!ex_tmp)) { PFATAL("alloc"); } - - for (i = 0; i <= (u32)len; ++i) { - - afl->stage_cur_byte = i; - - for (j = 0; j < afl->extras_cnt; ++j) { - - if (len + afl->extras[j].len > MAX_FILE) { - - --afl->stage_max; - continue; - - } - - /* Insert token */ - memcpy(ex_tmp + i, afl->extras[j].data, afl->extras[j].len); - - /* Copy tail */ - memcpy(ex_tmp + i + afl->extras[j].len, out_buf + i, len - i); - -#ifdef INTROSPECTION - snprintf(afl->mutation, sizeof(afl->mutation), "%s EXTRAS_insert-%u-%u", - afl->queue_cur->fname, i, j); -#endif - - if (common_fuzz_stuff(afl, ex_tmp, len + afl->extras[j].len)) { - - goto abandon_entry; - - } - - ++afl->stage_cur; - - } - - /* Copy head */ - ex_tmp[i] = out_buf[i]; - - } - - new_hit_cnt = afl->queued_items + afl->saved_crashes; - - afl->stage_finds[STAGE_EXTRAS_UI] += new_hit_cnt - orig_hit_cnt; - afl->stage_cycles[STAGE_EXTRAS_UI] += afl->stage_max; - -skip_user_extras: - - if (!afl->a_extras_cnt) { goto skip_extras; } - - afl->stage_name = "auto extras (over)"; - afl->stage_short = "ext_AO"; - afl->stage_cur = 0; - afl->stage_max = MIN(afl->a_extras_cnt, (u32)USE_AUTO_EXTRAS) * len; - - afl->stage_val_type = STAGE_VAL_NONE; - - orig_hit_cnt = new_hit_cnt; - - for (i = 0; i < (u32)len; ++i) { + for (i = 0; i < (u32)len; ++i) { u32 last_len = 0; afl->stage_cur_byte = i; - u32 min_extra_len = MIN(afl->a_extras_cnt, (u32)USE_AUTO_EXTRAS); - for (j = 0; j < min_extra_len; ++j) { + /* Extras are sorted by size, from smallest to largest. This means + that we don't have to worry about restoring the buffer in + between writes at a particular offset determined by the outer + loop. */ - /* See the comment in the earlier code; extras are sorted by size. */ + for (j = 0; j < afl->extras_cnt; ++j) { - if (afl->a_extras[j].len > len - i || - !memcmp(afl->a_extras[j].data, out_buf + i, afl->a_extras[j].len) || + /* Skip extras probabilistically if afl->extras_cnt > AFL_MAX_DET_EXTRAS. + Also skip them if there's no room to insert the payload, if the token + is redundant, or if its entire span has no bytes set in the effector + map. */ + + if ((afl->extras_cnt > afl->max_det_extras && + rand_below(afl, afl->extras_cnt) >= afl->max_det_extras) || + afl->extras[j].len > len - i || + !memcmp(afl->extras[j].data, out_buf + i, afl->extras[j].len) || !memchr(eff_map + EFF_APOS(i), 1, - EFF_SPAN_ALEN(i, afl->a_extras[j].len))) { + EFF_SPAN_ALEN(i, afl->extras[j].len))) { --afl->stage_max; continue; } - last_len = afl->a_extras[j].len; - memcpy(out_buf + i, afl->a_extras[j].data, last_len); + last_len = afl->extras[j].len; + memcpy(out_buf + i, afl->extras[j].data, last_len); #ifdef INTROSPECTION snprintf(afl->mutation, sizeof(afl->mutation), - "%s AUTO_EXTRAS_overwrite-%u-%u", afl->queue_cur->fname, i, j); + "%s EXTRAS_overwrite-%u-%u", afl->queue_cur->fname, i, j); #endif if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } @@ -1778,70 +1292,19 @@ u8 fuzz_one_original(afl_state_t *afl) { } /* Restore all the clobbered memory. */ - memcpy(out_buf + i, in_buf + i, last_len); + memcpy(out_buf + i, in_buf + i + afl->out_buf_offset, last_len); } new_hit_cnt = afl->queued_items + afl->saved_crashes; - afl->stage_finds[STAGE_EXTRAS_AO] += new_hit_cnt - orig_hit_cnt; - afl->stage_cycles[STAGE_EXTRAS_AO] += afl->stage_max; - - /* Insertion of auto extras. */ - - afl->stage_name = "auto extras (insert)"; - afl->stage_short = "ext_AI"; - afl->stage_cur = 0; - afl->stage_max = afl->a_extras_cnt * (len + 1); - - orig_hit_cnt = new_hit_cnt; - - ex_tmp = afl_realloc(AFL_BUF_PARAM(ex), len + MAX_DICT_FILE); - if (unlikely(!ex_tmp)) { PFATAL("alloc"); } - - for (i = 0; i <= (u32)len; ++i) { - - afl->stage_cur_byte = i; - - for (j = 0; j < afl->a_extras_cnt; ++j) { - - if (len + afl->a_extras[j].len > MAX_FILE) { - - --afl->stage_max; - continue; - - } - - /* Insert token */ - memcpy(ex_tmp + i, afl->a_extras[j].data, afl->a_extras[j].len); - - /* Copy tail */ - memcpy(ex_tmp + i + afl->a_extras[j].len, out_buf + i, len - i); - -#ifdef INTROSPECTION - snprintf(afl->mutation, sizeof(afl->mutation), - "%s AUTO_EXTRAS_insert-%u-%u", afl->queue_cur->fname, i, j); -#endif - - if (common_fuzz_stuff(afl, ex_tmp, len + afl->a_extras[j].len)) { - - goto abandon_entry; - - } - - ++afl->stage_cur; - - } - - /* Copy head */ - ex_tmp[i] = out_buf[i]; + afl->stage_finds[STAGE_EXTRAS_UO] += new_hit_cnt - orig_hit_cnt; + afl->stage_cycles[STAGE_EXTRAS_UO] += afl->stage_max; - } +skip_user_extras: - new_hit_cnt = afl->queued_items + afl->saved_crashes; + if (!afl->a_extras_cnt) { goto skip_extras; } - afl->stage_finds[STAGE_EXTRAS_AI] += new_hit_cnt - orig_hit_cnt; - afl->stage_cycles[STAGE_EXTRAS_AI] += afl->stage_max; skip_extras: @@ -1970,7 +1433,7 @@ u8 fuzz_one_original(afl_state_t *afl) { } /* out_buf may have been changed by the call to custom_fuzz */ - memcpy(out_buf, in_buf, len); + memcpy(out_buf, in_buf + afl->out_buf_offset, len); } @@ -2072,24 +1535,6 @@ u8 fuzz_one_original(afl_state_t *afl) { : 4) : 0); - if (unlikely(afl->expand_havoc && afl->ready_for_splicing_count > 1)) { - - /* add expensive havoc cases here, they are activated after a full - cycle without finds happened */ - - r_max += 4; - - } - - if (unlikely(get_cur_time() - afl->last_find_time > 5000 /* 5 seconds */ && - afl->ready_for_splicing_count > 1)) { - - /* add expensive havoc cases here if there is no findings in the last 5s */ - - r_max += 4; - - } - for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { u32 use_stacking = 1 << (1 + rand_below(afl, afl->havoc_stack_pow2)); @@ -2128,296 +1573,106 @@ u8 fuzz_one_original(afl_state_t *afl) { if (unlikely(!afl->out_buf)) { PFATAL("alloc"); } memcpy(out_buf, custom_havoc_buf, temp_len); - } - - } - - } - - }); - - } - - switch ((r = rand_below(afl, r_max))) { - - case 0 ... 3: { - - /* Flip a single bit somewhere. Spooky! */ - -#ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT1"); - strcat(afl->mutation, afl->m_tmp); -#endif - FLIP_BIT(out_buf, rand_below(afl, temp_len << 3)); - break; - - } - - case 4 ... 7: { - - /* Set byte to interesting value. */ - -#ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING8"); - strcat(afl->mutation, afl->m_tmp); -#endif - out_buf[rand_below(afl, temp_len)] = - interesting_8[rand_below(afl, sizeof(interesting_8))]; - break; - - } - - case 8 ... 9: { - - /* Set word to interesting value, little endian. */ - - if (temp_len < 2) { break; } - -#ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16"); - strcat(afl->mutation, afl->m_tmp); -#endif - *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = - interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)]; - - break; - - } - - case 10 ... 11: { - - /* Set word to interesting value, big endian. */ - - if (temp_len < 2) { break; } - -#ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16BE"); - strcat(afl->mutation, afl->m_tmp); -#endif - *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = SWAP16( - interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)]); - - break; - - } - - case 12 ... 13: { - - /* Set dword to interesting value, little endian. */ - - if (temp_len < 4) { break; } - -#ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32"); - strcat(afl->mutation, afl->m_tmp); -#endif - *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) = - interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)]; - - break; - - } - - case 14 ... 15: { - - /* Set dword to interesting value, big endian. */ - - if (temp_len < 4) { break; } - -#ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32BE"); - strcat(afl->mutation, afl->m_tmp); -#endif - *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) = SWAP32( - interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)]); - - break; - - } - - case 16 ... 19: { - - /* Randomly subtract from byte. */ - -#ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH8_"); - strcat(afl->mutation, afl->m_tmp); -#endif - out_buf[rand_below(afl, temp_len)] -= 1 + rand_below(afl, ARITH_MAX); - break; - - } - - case 20 ... 23: { - - /* Randomly add to byte. */ - -#ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH8+"); - strcat(afl->mutation, afl->m_tmp); -#endif - out_buf[rand_below(afl, temp_len)] += 1 + rand_below(afl, ARITH_MAX); - break; - - } - - case 24 ... 25: { - - /* Randomly subtract from word, little endian. */ - - if (temp_len < 2) { break; } - - u32 pos = rand_below(afl, temp_len - 1); - -#ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16_-%u", pos); - strcat(afl->mutation, afl->m_tmp); -#endif - *(u16 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX); - - break; - - } - - case 26 ... 27: { - - /* Randomly subtract from word, big endian. */ - - if (temp_len < 2) { break; } - - u32 pos = rand_below(afl, temp_len - 1); - u16 num = 1 + rand_below(afl, ARITH_MAX); - -#ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16_BE-%u_%u", pos, - num); - strcat(afl->mutation, afl->m_tmp); -#endif - *(u16 *)(out_buf + pos) = - SWAP16(SWAP16(*(u16 *)(out_buf + pos)) - num); + } - break; + } - } + } - case 28 ... 29: { + }); - /* Randomly add to word, little endian. */ + } - if (temp_len < 2) { break; } + switch ((r = rand_below(afl, r_max))) { + + case 0 ... 3: { - u32 pos = rand_below(afl, temp_len - 1); + /* Flip a single bit somewhere. Spooky! */ #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16+-%u", pos); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT1"); strcat(afl->mutation, afl->m_tmp); #endif - *(u16 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX); - + FLIP_BIT(out_buf, rand_below(afl, temp_len << 3)); break; } - case 30 ... 31: { - - /* Randomly add to word, big endian. */ - - if (temp_len < 2) { break; } + case 4 ... 7: { - u32 pos = rand_below(afl, temp_len - 1); - u16 num = 1 + rand_below(afl, ARITH_MAX); + /* Set byte to interesting value. */ #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16+BE-%u_%u", pos, - num); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING8"); strcat(afl->mutation, afl->m_tmp); #endif - *(u16 *)(out_buf + pos) = - SWAP16(SWAP16(*(u16 *)(out_buf + pos)) + num); - + out_buf[rand_below(afl, temp_len)] = + interesting_8[rand_below(afl, sizeof(interesting_8))]; break; } - case 32 ... 33: { - - /* Randomly subtract from dword, little endian. */ + case 8 ... 9: { - if (temp_len < 4) { break; } + /* Set word to interesting value, little endian. */ - u32 pos = rand_below(afl, temp_len - 3); + if (temp_len < 2) { break; } #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32_-%u", pos); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16"); strcat(afl->mutation, afl->m_tmp); #endif - *(u32 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX); + *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = + interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)]; break; } - case 34 ... 35: { - - /* Randomly subtract from dword, big endian. */ + case 10 ... 11: { - if (temp_len < 4) { break; } + /* Set word to interesting value, big endian. */ - u32 pos = rand_below(afl, temp_len - 3); - u32 num = 1 + rand_below(afl, ARITH_MAX); + if (temp_len < 2) { break; } #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32_BE-%u-%u", pos, - num); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16BE"); strcat(afl->mutation, afl->m_tmp); #endif - *(u32 *)(out_buf + pos) = - SWAP32(SWAP32(*(u32 *)(out_buf + pos)) - num); + *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = SWAP16( + interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)]); break; } - case 36 ... 37: { - - /* Randomly add to dword, little endian. */ - - if (temp_len < 4) { break; } + case 12 ... 13: { - u32 pos = rand_below(afl, temp_len - 3); + /* Randomly subtract from byte. */ #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32+-%u", pos); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH8_"); strcat(afl->mutation, afl->m_tmp); #endif - *(u32 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX); - + out_buf[rand_below(afl, temp_len)] -= 1 + rand_below(afl, ARITH_MAX); break; } - case 38 ... 39: { - - /* Randomly add to dword, big endian. */ - - if (temp_len < 4) { break; } + case 14 ... 15: { - u32 pos = rand_below(afl, temp_len - 3); - u32 num = 1 + rand_below(afl, ARITH_MAX); + /* Randomly add to byte. */ #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32+BE-%u-%u", pos, - num); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH8+"); strcat(afl->mutation, afl->m_tmp); #endif - *(u32 *)(out_buf + pos) = - SWAP32(SWAP32(*(u32 *)(out_buf + pos)) + num); - + out_buf[rand_below(afl, temp_len)] += 1 + rand_below(afl, ARITH_MAX); break; } - case 40 ... 43: { + case 16 ... 18: { /* Just set a random byte to a random value. Because, why not. We use XOR with 1-255 to eliminate the @@ -2432,116 +1687,7 @@ u8 fuzz_one_original(afl_state_t *afl) { } - case 44 ... 46: { - - if (temp_len + HAVOC_BLK_XL < MAX_FILE) { - - /* Clone bytes. */ - - u32 clone_len = choose_block_len(afl, temp_len); - u32 clone_from = rand_below(afl, temp_len - clone_len + 1); - u32 clone_to = rand_below(afl, temp_len); - -#ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " CLONE-%s-%u-%u-%u", - "clone", clone_from, clone_to, clone_len); - strcat(afl->mutation, afl->m_tmp); -#endif - u8 *new_buf = - afl_realloc(AFL_BUF_PARAM(out_scratch), temp_len + clone_len); - if (unlikely(!new_buf)) { PFATAL("alloc"); } - - /* Head */ - - memcpy(new_buf, out_buf, clone_to); - - /* Inserted part */ - - memcpy(new_buf + clone_to, out_buf + clone_from, clone_len); - - /* Tail */ - memcpy(new_buf + clone_to + clone_len, out_buf + clone_to, - temp_len - clone_to); - - out_buf = new_buf; - afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); - temp_len += clone_len; - - } - - break; - - } - - case 47: { - - if (temp_len + HAVOC_BLK_XL < MAX_FILE) { - - /* Insert a block of constant bytes (25%). */ - - u32 clone_len = choose_block_len(afl, HAVOC_BLK_XL); - u32 clone_to = rand_below(afl, temp_len); - -#ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " CLONE-%s-%u-%u", - "insert", clone_to, clone_len); - strcat(afl->mutation, afl->m_tmp); -#endif - u8 *new_buf = - afl_realloc(AFL_BUF_PARAM(out_scratch), temp_len + clone_len); - if (unlikely(!new_buf)) { PFATAL("alloc"); } - - /* Head */ - - memcpy(new_buf, out_buf, clone_to); - - /* Inserted part */ - - memset(new_buf + clone_to, - rand_below(afl, 2) ? rand_below(afl, 256) - : out_buf[rand_below(afl, temp_len)], - clone_len); - - /* Tail */ - memcpy(new_buf + clone_to + clone_len, out_buf + clone_to, - temp_len - clone_to); - - out_buf = new_buf; - afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); - temp_len += clone_len; - - } - - break; - - } - - case 48 ... 50: { - - /* Overwrite bytes with a randomly selected chunk bytes. */ - - if (temp_len < 2) { break; } - - u32 copy_len = choose_block_len(afl, temp_len - 1); - u32 copy_from = rand_below(afl, temp_len - copy_len + 1); - u32 copy_to = rand_below(afl, temp_len - copy_len + 1); - - if (likely(copy_from != copy_to)) { - -#ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " OVERWRITE_COPY-%u-%u-%u", - copy_from, copy_to, copy_len); - strcat(afl->mutation, afl->m_tmp); -#endif - memmove(out_buf + copy_to, out_buf + copy_from, copy_len); - - } - - break; - - } - - case 51: { + case 19: { /* Overwrite bytes with fixed bytes. */ @@ -2564,7 +1710,7 @@ u8 fuzz_one_original(afl_state_t *afl) { } - case 52: { + case 20: { /* Increase byte by 1. */ @@ -2577,7 +1723,7 @@ u8 fuzz_one_original(afl_state_t *afl) { } - case 53: { + case 21: { /* Decrease byte by 1. */ @@ -2590,7 +1736,7 @@ u8 fuzz_one_original(afl_state_t *afl) { } - case 54: { + case 22: { /* Flip byte. */ @@ -2603,84 +1749,6 @@ u8 fuzz_one_original(afl_state_t *afl) { } - case 55 ... 56: { - - if (temp_len < 4) { break; } - - /* Switch bytes. */ - - u32 to_end, switch_to, switch_len, switch_from; - switch_from = rand_below(afl, temp_len); - do { - - switch_to = rand_below(afl, temp_len); - - } while (switch_from == switch_to); - - if (switch_from < switch_to) { - - switch_len = switch_to - switch_from; - to_end = temp_len - switch_to; - - } else { - - switch_len = switch_from - switch_to; - to_end = temp_len - switch_from; - - } - - switch_len = choose_block_len(afl, MIN(switch_len, to_end)); - -#ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " SWITCH-%s-%u-%u-%u", - "switch", switch_from, switch_to, switch_len); - strcat(afl->mutation, afl->m_tmp); -#endif - u8 *new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), switch_len); - if (unlikely(!new_buf)) { PFATAL("alloc"); } - - /* Backup */ - - memcpy(new_buf, out_buf + switch_from, switch_len); - - /* Switch 1 */ - - memcpy(out_buf + switch_from, out_buf + switch_to, switch_len); - - /* Switch 2 */ - - memcpy(out_buf + switch_to, new_buf, switch_len); - - break; - - } - - // MAX_HAVOC_ENTRY = 64 - case 57 ... MAX_HAVOC_ENTRY: { - - /* Delete bytes. */ - - if (temp_len < 2) { break; } - - /* Don't delete too much. */ - - u32 del_len = choose_block_len(afl, temp_len - 1); - u32 del_from = rand_below(afl, temp_len - del_len + 1); - -#ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " DEL-%u-%u", del_from, - del_len); - strcat(afl->mutation, afl->m_tmp); -#endif - memmove(out_buf + del_from, out_buf + del_from + del_len, - temp_len - del_from - del_len); - - temp_len -= del_len; - - break; - - } - default: r -= (MAX_HAVOC_ENTRY + 1); @@ -2742,147 +1810,6 @@ u8 fuzz_one_original(afl_state_t *afl) { } - if (afl->a_extras_cnt) { - - u32 r_cmp = 2; - - if (unlikely(afl->cmplog_binary && afl->queue_cur->is_ascii)) { - - r_cmp = MUTATE_ASCII_DICT >> 1; - - } - - if (r < r_cmp) { - - /* Use the dictionary. */ - - u32 use_extra = rand_below(afl, afl->a_extras_cnt); - u32 extra_len = afl->a_extras[use_extra].len; - - if (extra_len > temp_len) { break; } - - u32 insert_at = rand_below(afl, temp_len - extra_len + 1); -#ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), - " AUTO_EXTRA_OVERWRITE-%u-%u", insert_at, extra_len); - strcat(afl->mutation, afl->m_tmp); -#endif - memcpy(out_buf + insert_at, afl->a_extras[use_extra].data, - extra_len); - - break; - - } else if (r < (r_cmp << 1)) { - - u32 use_extra = rand_below(afl, afl->a_extras_cnt); - u32 extra_len = afl->a_extras[use_extra].len; - if (temp_len + extra_len >= MAX_FILE) { break; } - - u8 *ptr = afl->a_extras[use_extra].data; - u32 insert_at = rand_below(afl, temp_len + 1); -#ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), - " AUTO_EXTRA_INSERT-%u-%u", insert_at, extra_len); - strcat(afl->mutation, afl->m_tmp); -#endif - - out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len + extra_len); - if (unlikely(!out_buf)) { PFATAL("alloc"); } - - /* Tail */ - memmove(out_buf + insert_at + extra_len, out_buf + insert_at, - temp_len - insert_at); - - /* Inserted part */ - memcpy(out_buf + insert_at, ptr, extra_len); - temp_len += extra_len; - - break; - - } else { - - r -= (r_cmp << 1); - - } - - } - - /* Splicing otherwise if we are still here. - Overwrite bytes with a randomly selected chunk from another - testcase or insert that chunk. */ - - /* Pick a random queue entry and seek to it. */ - - u32 tid; - do { - - tid = rand_below(afl, afl->queued_items); - - } while (tid == afl->current_entry || afl->queue_buf[tid]->len < 4); - - /* Get the testcase for splicing. */ - struct queue_entry *target = afl->queue_buf[tid]; - u32 new_len = target->len; - u8 *new_buf = queue_testcase_get(afl, target); - - if ((temp_len >= 2 && r % 2) || temp_len + HAVOC_BLK_XL >= MAX_FILE) { - - /* overwrite mode */ - - u32 copy_from, copy_to, copy_len; - - copy_len = choose_block_len(afl, new_len - 1); - if (copy_len > temp_len) copy_len = temp_len; - - copy_from = rand_below(afl, new_len - copy_len + 1); - copy_to = rand_below(afl, temp_len - copy_len + 1); - -#ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), - " SPLICE_OVERWRITE-%u-%u-%u-%s", copy_from, copy_to, - copy_len, target->fname); - strcat(afl->mutation, afl->m_tmp); -#endif - memmove(out_buf + copy_to, new_buf + copy_from, copy_len); - - } else { - - /* insert mode */ - - u32 clone_from, clone_to, clone_len; - - clone_len = choose_block_len(afl, new_len); - clone_from = rand_below(afl, new_len - clone_len + 1); - clone_to = rand_below(afl, temp_len + 1); - - u8 *temp_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), - temp_len + clone_len + 1); - if (unlikely(!temp_buf)) { PFATAL("alloc"); } - -#ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), - " SPLICE_INSERT-%u-%u-%u-%s", clone_from, clone_to, - clone_len, target->fname); - strcat(afl->mutation, afl->m_tmp); -#endif - /* Head */ - - memcpy(temp_buf, out_buf, clone_to); - - /* Inserted part */ - - memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len); - - /* Tail */ - memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to, - temp_len - clone_to); - - out_buf = temp_buf; - afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); - temp_len += clone_len; - - } - break; // end of default @@ -2891,15 +1818,16 @@ u8 fuzz_one_original(afl_state_t *afl) { } - if (common_fuzz_stuff(afl, out_buf, temp_len)) { goto abandon_entry; } + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } /* out_buf might have been mangled a bit, so let's restore it to its original size and shape. */ - out_buf = afl_realloc(AFL_BUF_PARAM(out), len); + out_buf = afl_realloc(AFL_BUF_PARAM(out), len + afl->out_buf_offset); if (unlikely(!out_buf)) { PFATAL("alloc"); } - temp_len = len; - memcpy(out_buf, in_buf, len); + temp_len = len + afl->out_buf_offset; + out_buf += afl->out_buf_offset; + memcpy(out_buf, in_buf + afl->out_buf_offset, len); /* If we're finding new stuff, let's run for a bit longer, limits permitting. */ @@ -2946,66 +1874,6 @@ u8 fuzz_one_original(afl_state_t *afl) { retry_splicing: - if (afl->use_splicing && splice_cycle++ < SPLICE_CYCLES && - afl->ready_for_splicing_count > 1 && afl->queue_cur->len >= 4) { - - struct queue_entry *target; - u32 tid, split_at; - u8 *new_buf; - s32 f_diff, l_diff; - - /* First of all, if we've modified in_buf for havoc, let's clean that - up... */ - - if (in_buf != orig_in) { - - in_buf = orig_in; - len = afl->queue_cur->len; - - } - - /* Pick a random queue entry and seek to it. Don't splice with yourself. */ - - do { - - tid = rand_below(afl, afl->queued_items); - - } while (tid == afl->current_entry || afl->queue_buf[tid]->len < 4); - - /* Get the testcase */ - afl->splicing_with = tid; - target = afl->queue_buf[tid]; - new_buf = queue_testcase_get(afl, target); - - /* Find a suitable splicing location, somewhere between the first and - the last differing byte. Bail out if the difference is just a single - byte or so. */ - - locate_diffs(in_buf, new_buf, MIN(len, (s64)target->len), &f_diff, &l_diff); - - if (f_diff < 0 || l_diff < 2 || f_diff == l_diff) { goto retry_splicing; } - - /* Split somewhere between the first and last differing byte. */ - - split_at = f_diff + rand_below(afl, l_diff - f_diff); - - /* Do the thing. */ - - len = target->len; - afl->in_scratch_buf = afl_realloc(AFL_BUF_PARAM(in_scratch), len); - memcpy(afl->in_scratch_buf, in_buf, split_at); - memcpy(afl->in_scratch_buf + split_at, new_buf, len - split_at); - in_buf = afl->in_scratch_buf; - afl_swap_bufs(AFL_BUF_PARAM(in), AFL_BUF_PARAM(in_scratch)); - - out_buf = afl_realloc(AFL_BUF_PARAM(out), len); - if (unlikely(!out_buf)) { PFATAL("alloc"); } - memcpy(out_buf, in_buf, len); - - goto custom_mutator_stage; - - } - #endif /* !IGNORE_FINDS */ ret_val = 0; @@ -3119,7 +1987,8 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { orig_in = in_buf = queue_testcase_get(afl, afl->queue_cur); len = afl->queue_cur->len; - out_buf = afl_realloc(AFL_BUF_PARAM(out), len); + // Adding 4 to len to accommodate the meta data + out_buf = afl_realloc(AFL_BUF_PARAM(out), len+4); if (unlikely(!out_buf)) { PFATAL("alloc"); } afl->subseq_tmouts = 0; @@ -3194,7 +2063,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { } - memcpy(out_buf, in_buf, len); + memcpy(out_buf, in_buf + afl->out_buf_offset, len); /********************* * PERFORMANCE SCORE * @@ -4312,7 +3181,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { } /* Restore all the clobbered memory. */ - memcpy(out_buf + i, in_buf + i, last_len); + memcpy(out_buf + i, in_buf + i + afl->out_buf_offset, last_len); } /* for i = 0; i < len */ @@ -4427,7 +3296,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { } /* Restore all the clobbered memory. */ - memcpy(out_buf + i, in_buf + i, last_len); + memcpy(out_buf + i, in_buf + i + afl->out_buf_offset, last_len); } /* for i = 0; i < len */ @@ -5252,7 +4121,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { out_buf = afl_realloc(AFL_BUF_PARAM(out), len); if (unlikely(!out_buf)) { PFATAL("alloc"); } temp_len = len; - memcpy(out_buf, in_buf, len); + memcpy(out_buf, in_buf + afl->out_buf_offset, len); /* If we're finding new stuff, let's run for a bit longer, limits permitting. */ @@ -5395,7 +4264,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { out_buf = afl_realloc(AFL_BUF_PARAM(out), len); if (unlikely(!out_buf)) { PFATAL("alloc"); } - memcpy(out_buf, in_buf, len); + memcpy(out_buf, in_buf + afl->out_buf_offset, len); goto havoc_stage_puppet; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index ee4a329801..1ea57cf86a 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -69,9 +69,333 @@ fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) { } + +// fsrv_run_result_t __attribute__((hot)) +// fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) { + +// #ifdef PROFILING +// static u64 time_spent_start = 0; +// struct timespec spec; +// if (time_spent_start) { + +// u64 current; +// clock_gettime(CLOCK_REALTIME, &spec); +// current = (spec.tv_sec * 1000000000) + spec.tv_nsec; +// time_spent_working += (current - time_spent_start); + +// } + +// #endif + +// fsrv_run_result_t res = afl_fsrv_run_target(fsrv, timeout, &afl->stop_soon); + +// #ifdef PROFILING +// clock_gettime(CLOCK_REALTIME, &spec); +// time_spent_start = (spec.tv_sec * 1000000000) + spec.tv_nsec; +// #endif + +// return res; + +// } + +// void write_buffer_to_file(char *buffer, size_t buffer_size) { +// // Get current time +// time_t current_time = time(NULL); + +// // Generate timestamp string +// char timestamp[20]; +// strftime(timestamp, sizeof(timestamp), "%Y%m%d_%H%M%S", localtime(¤t_time)); + +// // Create filename with timestamp appended +// char filename[256]; +// snprintf(filename, sizeof(filename), "/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/rough/output_%s.txt", timestamp); + +// // Open the file for writing +// FILE *fp = fopen(filename, "w"); +// if (fp == NULL) { +// perror("Error opening file for writing"); +// exit(EXIT_FAILURE); +// } + +// // Write the buffer to the file +// fwrite(buffer, buffer_size, 1, fp); + +// // Close the file +// fclose(fp); +// } + +// /* Write modified data to file for testing. If afl->fsrv.out_file is set, the +// old file is unlinked and a new one is created. Otherwise, afl->fsrv.out_fd is +// rewound and truncated. +// When calling the postprocessor, new_mem represents the input from the queue +// while new_buf represents the output from the postprocessor */ + +// int hex_to_int(char c) { +// if (c >= '0' && c <= '9') { +// return c - '0'; +// } else if (c >= 'a' && c <= 'f') { +// return c - 'a' + 10; +// } else if (c >= 'A' && c <= 'F') { +// return c - 'A' + 10; +// } else { +// return -1; +// } +// } + +// char* hex_encode(const unsigned char* data, size_t input_length, size_t* output_length) { +// size_t hex_string_size = input_length * 2 + 1; +// char *encoded_data = malloc(hex_string_size); + +// for (size_t i = 0; i < input_length; i++) { +// snprintf(encoded_data + (i * 2), hex_string_size - (i * 2), "%02x", data[i]); +// } +// encoded_data[hex_string_size - 1] = '\0'; + +// printf("encoded_data: %s hex_string_size: %ld input_length: %ld \n", encoded_data, hex_string_size, input_length); + +// *output_length = hex_string_size - 1; + +// return encoded_data; +// } + +// unsigned char* hex_decode(const char* data, size_t input_length, size_t* output_length) { + +// if (input_length % 2 != 0) { +// *output_length = 0; +// return NULL; +// } + +// size_t decoded_data_size = input_length / 2; +// unsigned char *decoded_data = malloc(decoded_data_size); + +// for (size_t i = 0; i < decoded_data_size; i++) { +// int hi = hex_to_int(data[i * 2]); +// int lo = hex_to_int(data[i * 2 + 1]); +// if (hi == -1 || lo == -1) { +// *output_length = 0; +// return NULL; +// } +// decoded_data[i] = (unsigned char)((hi << 4) | lo); +// } + +// *output_length = decoded_data_size; + +// return decoded_data; +// } + + +// u32 __attribute__((hot)) +// write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) { + +// if (unlikely(afl->custom_mutators_count)) { + +// ssize_t new_size = len; +// u8 *new_mem = *mem; +// u8 *new_buf = NULL; + +// u8 min_length = new_mem[2]; +// u8 max_length = new_mem[3]; + +// //printf("Fuzz seed min length: %d \n", min_length); +// //printf("Fuzz seed max length: %d \n", max_length); + +// if (unlikely(new_size < min_length)) { + +// return 0; + +// } else if (unlikely(new_size > max_length)) { + +// // new_size = max_length; + +// } + + +// printf("len: %d new_size: %d max_length: %d \n", len, new_size, max_length); + +// // Call python script to postprocess +// char command[1024]; +// char* encoded_buf = hex_encode(new_mem, new_size, &new_size); +// snprintf(command, sizeof(command), "python3 /home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/example.py %s", encoded_buf); +// free(encoded_buf); + +// // Open a pipe to the command and read its output +// FILE *fp = popen(command, "r"); +// if (fp == NULL) { +// perror("Error opening pipe to post-processor"); +// return 0; +// } + +// // Read the output of the command into a buffer +// char output_buf[1024]; +// size_t output_len = fread(output_buf, 1, sizeof(output_buf), fp); + +// // Close the pipe +// int status = pclose(fp); +// if (status == -1) { +// perror("Error closing pipe to command"); +// return 0; +// } else if (WIFEXITED(status)) { +// if (WEXITSTATUS(status) != 0) { +// fprintf(stderr, "Command %s exited with non-zero status %d\n", command, WEXITSTATUS(status)); +// return 0; +// } +// } else if (WIFSIGNALED(status)) { +// fprintf(stderr, "Command killed by signal %d\n", WTERMSIG(status)); +// return 0; +// } else { +// fprintf(stderr, "Command terminated abnormally\n"); +// return 0; +// } + +// if (output_len == sizeof(output_buf)) { +// fprintf(stderr, "Output buffer too small for command output\n"); +// return 0; +// } else if (output_len == 0) { +// fprintf(stderr, "Command produced no output\n"); +// return 0; +// } else { +// // We assume we read the hex string from stdout, so we need to add a null terminator +// output_buf[output_len] = '\0'; +// } + +// // Decode the output from base64 and store it in new_buf (remember to free it later) +// new_buf = hex_decode(output_buf, output_len, &new_size); + +// // Display a success message +// printf("Successfully post-processed data with new size: %d and buffer: %p\n", new_size, new_buf); + +// // Do something with new_buf + +// if (unlikely(!new_buf || new_size <= 0)) { + +// new_size = 0; +// new_buf = new_mem; +// // FATAL("Custom_post_process failed (ret: %lu)", (long +// // unsigned)new_size); + +// } else { + +// new_mem = new_buf; +// write_buffer_to_file(new_mem, new_size); + +// } + + + + + +// // LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { + +// // if (el->afl_custom_post_process) { + +// // new_size = +// // el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf); + +// // if (unlikely(!new_buf || new_size <= 0)) { + +// // new_size = 0; +// // new_buf = new_mem; +// // // FATAL("Custom_post_process failed (ret: %lu)", (long +// // // unsigned)new_size); + +// // } else { + +// // new_mem = new_buf; + +// // } + +// // } + +// // }); + +// if (unlikely(!new_size)) { + +// // perform dummy runs (fix = 1), but skip all others +// if (fix) { + +// new_size = len; + +// } else { + +// return 0; + +// } + +// } + +// if (unlikely(new_size < afl->min_length && !fix)) { + +// new_size = afl->min_length; + +// } else if (unlikely(new_size > afl->max_length)) { + +// new_size = afl->max_length; + +// } + +// /* +// I will be making some changes here so that the buffer returned from the postprocessor +// is not propagated back to the calling function. +// 1. If the postprocessor returns a buffer, the returned buffer will be written to the file. +// 2. The original buffer wont be updated and the original length would be returned. +// */ + +// // if (new_mem != *mem) { *mem = new_mem; } + +// /* everything as planned. use the potentially new data. */ +// afl_fsrv_write_to_testcase(&afl->fsrv, new_mem, new_size); +// //len = new_size; + +// // Free the memory used by new_buf +// free(new_buf); + + +// } else { + +// if (unlikely(len < afl->min_length && !fix)) { + +// len = afl->min_length; + +// } else if (unlikely(len > afl->max_length)) { + +// len = afl->max_length; + +// } + +// /* boring uncustom. */ +// afl_fsrv_write_to_testcase(&afl->fsrv, *mem, len); + +// } + +// #ifdef _AFL_DOCUMENT_MUTATIONS +// s32 doc_fd; +// char fn[PATH_MAX]; +// snprintf(fn, PATH_MAX, "%s/mutations/%09u:%s", afl->out_dir, +// afl->document_counter++, +// describe_op(afl, 0, NAME_MAX - strlen("000000000:"))); + +// if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION)) >= +// 0) { + +// if (write(doc_fd, *mem, len) != len) +// PFATAL("write to mutation file failed: %s", fn); +// close(doc_fd); + +// } + +// #endif + +// return len; + +// } + + + /* Write modified data to file for testing. If afl->fsrv.out_file is set, the old file is unlinked and a new one is created. Otherwise, afl->fsrv.out_fd is - rewound and truncated. */ + rewound and truncated. + When calling the postprocessor, new_mem represents the input from the queue + while new_buf represents the output from the postprocessor */ u32 __attribute__((hot)) write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) { @@ -82,29 +406,115 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) { u8 *new_mem = *mem; u8 *new_buf = NULL; - LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { + u8 min_length = new_mem[2]; + u8 max_length = new_mem[3]; - if (el->afl_custom_post_process) { + //printf("Fuzz seed min length: %d \n", min_length); + //printf("Fuzz seed max length: %d \n", max_length); - new_size = - el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf); + if (unlikely(new_size < min_length)) { - if (unlikely(!new_buf || new_size <= 0)) { + new_size = min_length; - new_size = 0; - new_buf = new_mem; - // FATAL("Custom_post_process failed (ret: %lu)", (long - // unsigned)new_size); + } else if (unlikely(new_size > max_length)) { - } else { + new_size = max_length; - new_mem = new_buf; + } - } - } + // Write new_mem to file - }); + + + FILE *fp_in = fopen(afl->seed_file, "wb"); + + if (fp_in == NULL) { + printf("Error initializing post-processor input...\n"); + exit(-1); + } + fwrite(new_mem, 1, new_size, fp_in); + fclose(fp_in); + + // Call python script to postprocess + const char* pd_command = "/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/example.py"; + const char* pd_path = "/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/"; + + + char cmd[1024]; + snprintf(cmd, sizeof(cmd), "python3 %s %s %s", pd_command, afl->seed_file, pd_path); + + + system(cmd); + + // Read content of the postprocessed file to new_buf + FILE *fp_out = fopen(afl->pd_script_file, "r"); + fseek(fp_out, 0, SEEK_END); + new_size = ftell(fp_out); + fseek(fp_out, 0, SEEK_SET); /* same as rewind(f); */ + new_buf = malloc(new_size); + fread(new_buf, new_size, 1, fp_out); + fclose(fp_out); + + // fclose(fp2); + + // struct stat st; + + // // Get information about the file + // if (stat("/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/original_fuzz_seed.pd", &st) == -1) { + // printf("Calling stat failed...\n"); + // exit(EXIT_FAILURE); + // } + + // new_size = st.st_size; + // new_buf = malloc(new_size); + // memcpy(new_buf, afl->mmap_out, new_size); + + // const int SIZE = 4096; + + // // Reset the memory locations + // memset(afl->mmap_in, 0, SIZE); + // memset(afl->mmap_out, 0, SIZE); + + + if (unlikely(!new_buf || new_size <= 0)) { + + new_size = 0; + new_buf = new_mem; + // FATAL("Custom_post_process failed (ret: %lu)", (long + // unsigned)new_size); + + } else { + + new_mem = new_buf; + + } + + + + // LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { + + // if (el->afl_custom_post_process) { + + // new_size = + // el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf); + + // if (unlikely(!new_buf || new_size <= 0)) { + + // new_size = 0; + // new_buf = new_mem; + // // FATAL("Custom_post_process failed (ret: %lu)", (long + // // unsigned)new_size); + + // } else { + + // new_mem = new_buf; + + // } + + // } + + // }); if (unlikely(!new_size)) { @@ -131,11 +541,18 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) { } - if (new_mem != *mem) { *mem = new_mem; } + /* + I will be making some changes here so that the buffer returned from the postprocessor + is not propagated back to the calling function. + 1. If the postprocessor returns a buffer, the returned buffer will be written to the file. + 2. The original buffer wont be updated and the original length would be returned. + */ + + // if (new_mem != *mem) { *mem = new_mem; } /* everything as planned. use the potentially new data. */ - afl_fsrv_write_to_testcase(&afl->fsrv, *mem, new_size); - len = new_size; + afl_fsrv_write_to_testcase(&afl->fsrv, new_mem, new_size); + //len = new_size; } else { @@ -987,9 +1404,27 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { error conditions, returning 1 if it's time to bail out. This is a helper function for fuzz_one(). */ +static int fuzz_count = 0; + u8 __attribute__((hot)) common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { + if (afl->out_buf_offset > 0) { + // Rollback out_buf pointer to point to beginning of buffer + out_buf -= afl->out_buf_offset; + len += afl->out_buf_offset; + } + + if (len < 2) { + // The buffer doesn't have space for script id + return 0; + } + + // Set packetdrill script type based on fuzz_count + u8 script_id = (fuzz_count++ / 1000); + *(out_buf+1) = script_id; + //printf("Inserting to buffer: Fuzz count: %d Script id: %d\n", fuzz_count-1, script_id); + u8 fault; if (unlikely(len = write_to_testcase(afl, (void **)&out_buf, len, 0)) == 0) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 294c42f6bb..5ed6e60010 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -381,6 +381,41 @@ static int stricmp(char const *a, char const *b) { } +const int SIZE = 4096; + +void afl_pp_file_deinit(afl_state_t *afl) { + /* Free pointers to post-processor file names */ + + free(afl->seed_file); + free(afl->pd_script_file); +} + +void afl_pp_file_init(afl_state_t *afl) { + + char *seed_file_template = "/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/fuzz_seed"; + char *seed_file; + + const char *interface_name = getenv("TAP_INTERFACE_NAME"); + + if (interface_name != NULL) { + int len = strlen(interface_name) + strlen(seed_file_template) + 2; + seed_file = malloc(len * sizeof(char)); + snprintf(seed_file, len, "%s_%s", seed_file_template, interface_name); + } else { + seed_file = strdup(seed_file_template); + } + + + int pd_script_len = strlen(seed_file) + 4; + char *pd_script_file = malloc(pd_script_len * sizeof(char)); + snprintf(pd_script_file, pd_script_len, "%s%s", seed_file, ".pd"); + + + afl->seed_file = seed_file; + afl->pd_script_file = pd_script_file; + +} + static void fasan_check_afl_preload(char *afl_preload) { char first_preload[PATH_MAX + 1] = {0}; @@ -528,6 +563,7 @@ int main(int argc, char **argv_orig, char **envp) { afl->debug = debug; afl_fsrv_init(&afl->fsrv); if (debug) { afl->fsrv.debug = true; } + afl_pp_file_init(afl); read_afl_environment(afl, envp); if (afl->shm.map_size) { afl->fsrv.map_size = afl->shm.map_size; } exit_1 = !!afl->afl_env.afl_bench_just_one; @@ -2641,6 +2677,7 @@ int main(int argc, char **argv_orig, char **envp) { } afl_fsrv_deinit(&afl->fsrv); + afl_pp_file_deinit(afl); /* remove tmpfile */ if (afl->tmp_dir != NULL && !afl->in_place_resume && afl->fsrv.out_file) { diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl index 6e00ceac6f..f36786f0aa 160000 --- a/unicorn_mode/unicornafl +++ b/unicorn_mode/unicornafl @@ -1 +1 @@ -Subproject commit 6e00ceac6fd5627e42e1858c543c84f2fbdaedda +Subproject commit f36786f0aa42c3ba665fac9391ce253269ee213d