From 27f97caf5a37270feb383d433a3c053b4a04b0ab Mon Sep 17 00:00:00 2001 From: AmPaschal Date: Mon, 24 Oct 2022 19:54:39 +0000 Subject: [PATCH 01/10] Added support to run AFL++ on FreeRTOS and PacketDrill --- include/forkserver.h | 3 + instrumentation/afl-compiler-rt.o.c | 2 + src/afl-forkserver.c | 91 +++++++++++++++++++++++++++-- src/afl-fuzz-init.c | 17 ++++++ 4 files changed, 107 insertions(+), 6 deletions(-) diff --git a/include/forkserver.h b/include/forkserver.h index 59ce0ee7bb..437b53c6ee 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -85,7 +85,9 @@ typedef struct afl_forkserver { s32 fsrv_pid, /* PID of the fork server */ child_pid, /* PID of the fuzzed program */ + pd_pid, /* PID of 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 +205,7 @@ 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/src/afl-forkserver.c b/src/afl-forkserver.c index 628ff590e7..0197e8d8be 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -1267,6 +1267,34 @@ void afl_fsrv_kill(afl_forkserver_t *fsrv) { } +void handle_timeout_fsrv(afl_forkserver_t *fsrv) { + + 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 */ + + s32 tmp_pid = fsrv->child_pid; + if (tmp_pid > 0) { + + kill(tmp_pid, fsrv->kill_signal); + fsrv->child_pid = -1; + + } + + fsrv->last_run_timed_out = 1; + } +} + + +void handle_timeout() { + + 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, @@ -1534,13 +1562,64 @@ 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; + + it.it_value.tv_sec = (timeout / 1000); + it.it_value.tv_usec = (timeout % 1000) * 1000; + + setitimer(ITIMER_REAL, &it, NULL); + + pid_t pd_pid = fork(); + if (pd_pid==0) { /* child process */ + + static char *argv[]={"/home/pamusuo/research/ampaschal-packetdrill/gtests/net/packetdrill/packetdrill", + "--so_filename=/home/pamusuo/research/rtos-fuzzing/rtos-bridge/libfreertos-bridge.so", + "--local_ip=125.0.75.0", + "--non_fatal=packet", + "--tolerance_usecs=1000000", + "/home/pamusuo/research/ampaschal-packetdrill/gtests/net/tcp/blocking/blocking-accept.pkt", NULL}; + 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 */ + } - if (exec_ms > timeout) { + fsrv->pd_pid = pd_pid; - /* If there was no response from forkserver after timeout seconds, - we kill the child. The forkserver should inform us afterwards */ + restart_read: + res = read(fsrv->fsrv_st_fd, &fsrv->child_status, 4); + + 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; + + setitimer(ITIMER_REAL, &it, NULL); + + + /* 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 +1632,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..5090cc90c4 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,17 @@ static void handle_skipreq(int sig) { } + + +/* Handle timeout (SIGALRM). */ + +static void handle_timeout_signal(int sig) { + + (void)sig; + handle_timeout(); + +} + /* Setup shared map for fuzzing with input via sharedmem */ void setup_testcase_shmem(afl_state_t *afl) { @@ -2914,6 +2926,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; From dcb528b6c6c9b37e885ed0788161f3371c7afebf Mon Sep 17 00:00:00 2001 From: AmPaschal Date: Wed, 9 Nov 2022 20:04:59 +0000 Subject: [PATCH 02/10] Setup postprocessor for AFL --- custom_mutators/packetdrill/common.py | 40 +++ custom_mutators/packetdrill/example.py | 317 ++++++++++++++++++ custom_mutators/packetdrill/post_pd_fuzz.so.c | 77 +++++ src/afl-cc.c | 2 +- src/afl-forkserver.c | 10 +- 5 files changed, 442 insertions(+), 4 deletions(-) create mode 100644 custom_mutators/packetdrill/common.py create mode 100644 custom_mutators/packetdrill/example.py create mode 100644 custom_mutators/packetdrill/post_pd_fuzz.so.c 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..1990de66ac --- /dev/null +++ b/custom_mutators/packetdrill/example.py @@ -0,0 +1,317 @@ +#!/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 re + + +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 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: + print("Exception while opening the file"); + return []; + +fields = ["src_port", "dst_port", "seq_num", "ack_num", "header_length", "flags", "win_size", "checksum", "urg_pointer"]; + +fields = ["src_port","ack", "win", "mss"]; + +def generate_replace_inst(buf, current_counter): + + field_index = buf[current_counter] % len(fields); + + current_counter += 1; + + field = fields[field_index]; + + inst = "rep"; + if (field == "src_port"): + src_port_bytes: bytearray = buf[current_counter: current_counter + 2]; + inst = inst + " tcp src_port 0x" + src_port_bytes.hex().capitalize(); + current_counter += 2; + + elif (field == "ack"): + src_port_bytes: bytearray = buf[current_counter: current_counter + 4]; + inst = inst + " tcp ack 0x" + src_port_bytes.hex().capitalize(); + current_counter += 2; + + elif (field == "win"): + src_port_bytes: bytearray = buf[current_counter: current_counter + 2]; + inst = inst + " tcp win 0x" + src_port_bytes.hex().capitalize(); + current_counter += 2; + + elif (field == "mss"): + src_port_bytes: bytearray = buf[current_counter: current_counter + 2]; + inst = inst + " tcp mss 0x" + src_port_bytes.hex().capitalize(); + current_counter += 2; + + return current_counter, inst; + +MAX_INSERT_BYTES = 6; + +MAX_DELETE_BYTES = 6; + +def generate_insert_inst(buf, current_counter): + + insert_point = buf[current_counter]; + + 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]; + + insert_bytes = insert_bytes.hex().capitalize(); + + current_counter += num_insert_butes; + + return current_counter, f"ins tcp {insert_point} 0x{insert_bytes}"; + + +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}"; + + +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 + + if (len(buf) < 5): + return 0; + + current_counter = 0; + + pd_commands = get_pd_commands_from_script("/home/pamusuo/research/ampaschal-packetdrill/gtests/net/tcp/blocking/blocking-accept-fuzz.pkt"); + + first_byte = buf[current_counter]; + + current_counter += 1; + + start_index = first_byte % len(pd_commands); + + updated_commands = pd_commands[0: start_index] + + for i in range(start_index, len(pd_commands)): + + pd_command = pd_commands[i]; + + inbound_match = re.search("\+\d*\.?\d* < [S|F|P|\.]", pd_command); + + if (inbound_match is None or (len(buf) - current_counter) < 3): + updated_commands.append(pd_command); + continue; + + control_byte = buf[current_counter]; + + current_counter += 1; + + control = control_byte % 3; + + if control == 0: + (current_counter, inst) = generate_replace_inst(buf, current_counter); + elif control == 1: + (current_counter, inst) = generate_insert_inst(buf, current_counter); + else: + (current_counter, inst) = generate_delete_inst(buf, current_counter); + + if (inst == ""): + updated_commands.append(pd_command); + else: + fuzz_instruction = pd_command.strip() + ' {' + inst + '}\n'; + updated_commands.append(fuzz_instruction); + + 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); + + buf = bytearray(updated_command_string.encode()); + + return buf + + + + +# Uncomment and implement the following methods if you want to use a custom +# trimming algorithm. See also the documentation for a better API description. + +# def init_trim(buf): +# ''' +# Called per trimming iteration. +# +# @type buf: bytearray +# @param buf: The buffer that should be trimmed. +# +# @rtype: int +# @return: The maximum number of trimming steps. +# ''' +# global ... +# +# # Initialize global variables +# +# # Figure out how many trimming steps are possible. +# # If this is not possible for your trimming, you can +# # return 1 instead and always return 0 in post_trim +# # until you are done (then you return 1). +# +# return steps +# +# def trim(): +# ''' +# Called per trimming iteration. +# +# @rtype: bytearray +# @return: A new bytearray containing the trimmed data. +# ''' +# global ... +# +# # Implement the actual trimming here +# +# return bytearray(...) +# +# def post_trim(success): +# ''' +# Called after each trimming operation. +# +# @type success: bool +# @param success: Indicates if the last trim operation was successful. +# +# @rtype: int +# @return: The next trim index (0 to max number of steps) where max +# number of steps indicates the trimming is done. +# ''' +# global ... +# +# if not success: +# # Restore last known successful input, determine next index +# else: +# # Just determine the next index, based on what was successfully +# # removed in the last step +# +# return next_index +# +# 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 +# ''' +# return buf +# +# def havoc_mutation(buf, max_size): +# ''' +# Perform a single custom mutation on a given input. +# +# @type buf: bytearray +# @param buf: The buffer that should be mutated. +# +# @type max_size: int +# @param max_size: Maximum size of the mutated output. The mutation must not +# produce data larger than max_size. +# +# @rtype: bytearray +# @return: A new bytearray containing the mutated data +# ''' +# return mutated_buf +# +# def havoc_mutation_probability(): +# ''' +# Called for each `havoc_mutation`. Return the probability (in percentage) +# that `havoc_mutation` is called in havoc. Be default it is 6%. +# +# @rtype: int +# @return: The probability (0-100) +# ''' +# return prob +# +# def queue_get(filename): +# ''' +# Called at the beginning of each fuzz iteration to determine whether the +# test case should be fuzzed +# +# @type filename: str +# @param filename: File name of the test case in the current queue entry +# +# @rtype: bool +# @return: Return True if the custom mutator decides to fuzz the test case, +# and False otherwise +# ''' +# return True +# +# def queue_new_entry(filename_new_queue, filename_orig_queue): +# ''' +# Called after adding a new test case to the queue +# +# @type filename_new_queue: str +# @param filename_new_queue: File name of the new queue entry +# +# @type filename_orig_queue: str +# @param filename_orig_queue: File name of the original queue entry +# ''' +# pass 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/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 0197e8d8be..91050add0d 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -1569,15 +1569,19 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, setitimer(ITIMER_REAL, &it, NULL); + // 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 */ + + const char *pd_script = fsrv->out_file; - static char *argv[]={"/home/pamusuo/research/ampaschal-packetdrill/gtests/net/packetdrill/packetdrill", + 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", "--non_fatal=packet", - "--tolerance_usecs=1000000", - "/home/pamusuo/research/ampaschal-packetdrill/gtests/net/tcp/blocking/blocking-accept.pkt", NULL}; + "--tolerance_usecs=1000000", pd_script, NULL}; 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); From c6b21125f18834866a21434e1856cecd74730558 Mon Sep 17 00:00:00 2001 From: AmPaschal Date: Fri, 2 Dec 2022 19:38:59 +0000 Subject: [PATCH 03/10] Enable packetdrill fuzzing --- custom_mutators/packetdrill/example.py | 93 +++++++++++++++++++++++--- include/config.h | 2 +- include/forkserver.h | 2 + src/afl-forkserver.c | 87 +++++++++++++++++++++++- src/afl-fuzz-init.c | 1 + src/afl-fuzz-run.c | 17 +++-- 6 files changed, 186 insertions(+), 16 deletions(-) diff --git a/custom_mutators/packetdrill/example.py b/custom_mutators/packetdrill/example.py index 1990de66ac..d3943ef702 100644 --- a/custom_mutators/packetdrill/example.py +++ b/custom_mutators/packetdrill/example.py @@ -82,13 +82,15 @@ def generate_replace_inst(buf, current_counter): return current_counter, inst; -MAX_INSERT_BYTES = 6; +MAX_INSERT_BYTES = 4; MAX_DELETE_BYTES = 6; -def generate_insert_inst(buf, current_counter): +MAX_INSERT_POINT = 20; + +def generate_insert_random(buf, current_counter): - insert_point = buf[current_counter]; + insert_point = buf[current_counter] % MAX_INSERT_POINT; current_counter += 1; @@ -98,12 +100,79 @@ def generate_insert_inst(buf, current_counter): 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 + + #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 + + #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): @@ -130,11 +199,11 @@ def post_process(buf): # @return: The buffer containing the test case after if (len(buf) < 5): - return 0; + return bytes("", "utf-8"); current_counter = 0; - pd_commands = get_pd_commands_from_script("/home/pamusuo/research/ampaschal-packetdrill/gtests/net/tcp/blocking/blocking-accept-fuzz.pkt"); + pd_commands = get_pd_commands_from_script("/home/pamusuo/research/ampaschal-packetdrill/gtests/net/tcp/blocking/blocking-accept-fuzz-template.pkt"); first_byte = buf[current_counter]; @@ -165,7 +234,7 @@ def post_process(buf): elif control == 1: (current_counter, inst) = generate_insert_inst(buf, current_counter); else: - (current_counter, inst) = generate_delete_inst(buf, current_counter); + (current_counter, inst) = generate_truncate_tcp_header_inst(buf, current_counter); if (inst == ""): updated_commands.append(pd_command); @@ -177,12 +246,12 @@ def post_process(buf): updated_buf = bytearray(updated_command_string.encode()); - timestamp = calendar.timegm(time.gmtime()); + """ 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); + mutated_files.write(updated_buf); """ pd_command_string = ''.join(pd_commands); @@ -191,6 +260,14 @@ def post_process(buf): return buf +if __name__ == "__main__": + + buf = b"042af4" + + current_counter, inst = generate_truncate_tcp_header_inst(buf, 0) + + print(f"current counter: {current_counter}") + print("instruction: " + inst) # Uncomment and implement the following methods if you want to use a custom 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 437b53c6ee..2fa80718d9 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -207,6 +207,8 @@ 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 \ " - On MacOS X, the semantics of fork() syscalls are non-standard and " \ diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 91050add0d..040dd7dd3d 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -1269,18 +1269,35 @@ 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) { - kill(tmp_pid, fsrv->kill_signal); + 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; } } @@ -1288,6 +1305,8 @@ void handle_timeout_fsrv(afl_forkserver_t *fsrv) { void handle_timeout() { + printf("handle_timeout...\n"); + LIST_FOREACH(&fsrv_list, afl_forkserver_t, { handle_timeout_fsrv(el); @@ -1431,7 +1450,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__ @@ -1564,16 +1583,42 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, struct itimerval it; + //printf("timeout is %d...\n", timeout); + + 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; - setitimer(ITIMER_REAL, &it, NULL); + 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; // 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", @@ -1589,11 +1634,43 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, exit(127); /* only if execv fails */ } + /* + pid_t pd_pid = fork(); + if (pd_pid==0) { + + pd_pid = fork(); + + if (pd_pid == 0) { + + 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", + "--non_fatal=packet", + "--tolerance_usecs=1000000", pd_script, NULL}; + 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); + } else { + // Send the pid to parent + exit(0); + } + + + } + */ + 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); @@ -1614,7 +1691,11 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, 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, diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 5090cc90c4..7a1b138e91 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2562,6 +2562,7 @@ static void handle_skipreq(int sig) { static void handle_timeout_signal(int sig) { (void)sig; + printf("handle_timeout_signal"); handle_timeout(); } diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index ee4a329801..24ecd89a9d 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -71,7 +71,9 @@ fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) { /* 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) { @@ -131,11 +133,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 { From cf91d58413d82ecc9dfd749d873361933c580229 Mon Sep 17 00:00:00 2001 From: AmPaschal Date: Wed, 21 Dec 2022 03:37:02 +0000 Subject: [PATCH 04/10] Added support for dual-target fuzzing --- custom_mutators/packetdrill/example.py | 243 +++++++++---------------- include/forkserver.h | 1 + src/afl-forkserver.c | 106 ++++++++++- 3 files changed, 193 insertions(+), 157 deletions(-) diff --git a/custom_mutators/packetdrill/example.py b/custom_mutators/packetdrill/example.py index d3943ef702..2652d7d6ac 100644 --- a/custom_mutators/packetdrill/example.py +++ b/custom_mutators/packetdrill/example.py @@ -18,6 +18,8 @@ import time import random import re +import sys +import os def init(seed): @@ -47,41 +49,69 @@ def get_pd_commands_from_script(filename): print("Exception while opening the file"); return []; -fields = ["src_port", "dst_port", "seq_num", "ack_num", "header_length", "flags", "win_size", "checksum", "urg_pointer"]; +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"]; +#fields = ["src_port","ack", "win", "mss"]; -def generate_replace_inst(buf, current_counter): +def generate_replace_tcp_inst(buf, current_counter): - field_index = buf[current_counter] % len(fields); + field_index = buf[current_counter] % len(tcp_fields); current_counter += 1; - field = fields[field_index]; + field_dict = tcp_fields[field_index]; - inst = "rep"; - if (field == "src_port"): - src_port_bytes: bytearray = buf[current_counter: current_counter + 2]; - inst = inst + " tcp src_port 0x" + src_port_bytes.hex().capitalize(); - current_counter += 2; + if (current_counter + field_dict["no_bytes"] > len(buf)): + return current_counter - 1, "" - elif (field == "ack"): - src_port_bytes: bytearray = buf[current_counter: current_counter + 4]; - inst = inst + " tcp ack 0x" + src_port_bytes.hex().capitalize(); - current_counter += 2; + 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"]; - elif (field == "win"): - src_port_bytes: bytearray = buf[current_counter: current_counter + 2]; - inst = inst + " tcp win 0x" + src_port_bytes.hex().capitalize(); - current_counter += 2; + 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]; - elif (field == "mss"): - src_port_bytes: bytearray = buf[current_counter: current_counter + 2]; - inst = inst + " tcp mss 0x" + src_port_bytes.hex().capitalize(); - current_counter += 2; + 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; @@ -227,11 +257,13 @@ def post_process(buf): current_counter += 1; - control = control_byte % 3; + control = control_byte % 4; if control == 0: - (current_counter, inst) = generate_replace_inst(buf, current_counter); + (current_counter, inst) = generate_replace_tcp_inst(buf, current_counter); elif control == 1: + (current_counter, inst) = generate_replace_ip_inst(buf, current_counter); + elif control == 2: (current_counter, inst) = generate_insert_inst(buf, current_counter); else: (current_counter, inst) = generate_truncate_tcp_header_inst(buf, current_counter); @@ -255,140 +287,47 @@ def post_process(buf): pd_command_string = ''.join(pd_commands); - buf = bytearray(updated_command_string.encode()); - - return buf + return bytearray(updated_command_string.encode()); if __name__ == "__main__": - buf = b"042af4" + # Check if the user has provided two file paths + if len(sys.argv) != 3: + # If not, display an error message and exit + print("Error: please provide two file paths") + exit(1) + + # 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() + + processed_data = post_process(src_data) + + if (len(processed_data) == 0): + print("Post process retuned empty string") + exit(1) + + 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 + print(f"Successfully written post-processed data to {dest_file_name}") + + """ buf = b"042af4" current_counter, inst = generate_truncate_tcp_header_inst(buf, 0) print(f"current counter: {current_counter}") - print("instruction: " + inst) + print("instruction: " + inst) """ - -# Uncomment and implement the following methods if you want to use a custom -# trimming algorithm. See also the documentation for a better API description. - -# def init_trim(buf): -# ''' -# Called per trimming iteration. -# -# @type buf: bytearray -# @param buf: The buffer that should be trimmed. -# -# @rtype: int -# @return: The maximum number of trimming steps. -# ''' -# global ... -# -# # Initialize global variables -# -# # Figure out how many trimming steps are possible. -# # If this is not possible for your trimming, you can -# # return 1 instead and always return 0 in post_trim -# # until you are done (then you return 1). -# -# return steps -# -# def trim(): -# ''' -# Called per trimming iteration. -# -# @rtype: bytearray -# @return: A new bytearray containing the trimmed data. -# ''' -# global ... -# -# # Implement the actual trimming here -# -# return bytearray(...) -# -# def post_trim(success): -# ''' -# Called after each trimming operation. -# -# @type success: bool -# @param success: Indicates if the last trim operation was successful. -# -# @rtype: int -# @return: The next trim index (0 to max number of steps) where max -# number of steps indicates the trimming is done. -# ''' -# global ... -# -# if not success: -# # Restore last known successful input, determine next index -# else: -# # Just determine the next index, based on what was successfully -# # removed in the last step -# -# return next_index -# -# 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 -# ''' -# return buf -# -# def havoc_mutation(buf, max_size): -# ''' -# Perform a single custom mutation on a given input. -# -# @type buf: bytearray -# @param buf: The buffer that should be mutated. -# -# @type max_size: int -# @param max_size: Maximum size of the mutated output. The mutation must not -# produce data larger than max_size. -# -# @rtype: bytearray -# @return: A new bytearray containing the mutated data -# ''' -# return mutated_buf -# -# def havoc_mutation_probability(): -# ''' -# Called for each `havoc_mutation`. Return the probability (in percentage) -# that `havoc_mutation` is called in havoc. Be default it is 6%. -# -# @rtype: int -# @return: The probability (0-100) -# ''' -# return prob -# -# def queue_get(filename): -# ''' -# Called at the beginning of each fuzz iteration to determine whether the -# test case should be fuzzed -# -# @type filename: str -# @param filename: File name of the test case in the current queue entry -# -# @rtype: bool -# @return: Return True if the custom mutator decides to fuzz the test case, -# and False otherwise -# ''' -# return True -# -# def queue_new_entry(filename_new_queue, filename_orig_queue): -# ''' -# Called after adding a new test case to the queue -# -# @type filename_new_queue: str -# @param filename_new_queue: File name of the new queue entry -# -# @type filename_orig_queue: str -# @param filename_orig_queue: File name of the original queue entry -# ''' -# pass diff --git a/include/forkserver.h b/include/forkserver.h index 2fa80718d9..fc9276e74a 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -86,6 +86,7 @@ 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 */ diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 040dd7dd3d..fa330a9a54 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -48,6 +48,11 @@ #include #include #include +#include +#include +#include +#include +#include /** * The correct fds for reading and writing pipes @@ -374,6 +379,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 @@ -1027,6 +1088,23 @@ 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 + char tun_name[6]; + + /* Connect to the device */ + strcpy(tun_name, "tap0"); + int tun_fd = tun_alloc(tun_name, IFF_TAP | 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 succeeded with fd %d\n", tun_fd); + fsrv->pd_tap_fd = tun_fd; + } + } + return; } @@ -1604,17 +1682,23 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, 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); + // 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 */ + // 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 */ @@ -1627,7 +1711,19 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, "--local_ip=125.0.75.0", "--non_fatal=packet", "--tolerance_usecs=1000000", pd_script, NULL}; - res = execv("/home/pamusuo/research/ampaschal-packetdrill/gtests/net/packetdrill/packetdrill", argv); + + 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); } From 65e67e6e5c84c03497a1b65773507e60de103697 Mon Sep 17 00:00:00 2001 From: AmPaschal Date: Tue, 21 Feb 2023 17:06:51 +0000 Subject: [PATCH 05/10] Updated post processor --- custom_mutators/packetdrill/example.py | 135 +++++++++++++++++-------- 1 file changed, 95 insertions(+), 40 deletions(-) diff --git a/custom_mutators/packetdrill/example.py b/custom_mutators/packetdrill/example.py index 2652d7d6ac..af5d1cd64d 100644 --- a/custom_mutators/packetdrill/example.py +++ b/custom_mutators/packetdrill/example.py @@ -17,11 +17,14 @@ import calendar import time import random +import struct import re import sys import os +iter_index = 0 + def init(seed): """ Called once when AFLFuzz starts up. Used to seed our RNG. @@ -36,11 +39,11 @@ def deinit(): pass 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; @@ -217,6 +220,58 @@ def generate_delete_inst(buf, current_counter): 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, "INSERT_MSS", "ins tcp mss", True), + (1, "INSERT_IP_OPTION", "ins ipv4 20", True), + (2, "REPLACE_IPV4_HEADER_LENGTH", "rep ipv4 version_ihl", True), + (3, "REPLACE_TCP_HEADER_LENGTH", "rep tcp tcp_hdr_len", True), + (4, "TRUN_TCP_HEADER", "trun tcp 0", False), + (5, "REPLACE_IPV4_SOURCE_ADDR", "rep ipv4 src_ip", 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() + if len(value) == 0: + 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 @@ -228,66 +283,66 @@ def post_process(buf): # @rtype: bytearray # @return: The buffer containing the test case after - if (len(buf) < 5): - return bytes("", "utf-8"); + global iter_index - current_counter = 0; + if (len(buf) < 4): + return bytes("", "utf-8"); - pd_commands = get_pd_commands_from_script("/home/pamusuo/research/ampaschal-packetdrill/gtests/net/tcp/blocking/blocking-accept-fuzz-template.pkt"); + # print(f"Fuzz iteration {iter_index}") - first_byte = buf[current_counter]; - - current_counter += 1; + state_idx_to_fuzz = buf[1] % len(tcp_states) - start_index = first_byte % len(pd_commands); + state_to_fuzz = tcp_states[state_idx_to_fuzz] + iter_index = iter_index + 1 - updated_commands = pd_commands[0: start_index] + pd_commands = get_pd_commands_from_script(state_to_fuzz[1]); - for i in range(start_index, len(pd_commands)): + print(f"STate to fuzz: {state_to_fuzz}") + # print(f"Length of list: {len(pd_commands)}") - pd_command = pd_commands[i]; - - inbound_match = re.search("\+\d*\.?\d* < [S|F|P|\.]", pd_command); + fuzz_index = state_to_fuzz[2] - 1 + + pd_command = pd_commands[fuzz_index] - if (inbound_match is None or (len(buf) - current_counter) < 3): - updated_commands.append(pd_command); - continue; + #updated_commands = pd_commands[:-1] + updated_commands = pd_commands[0: fuzz_index] - control_byte = buf[current_counter]; + inbound_match = re.search("\+\d*\.?\d* < [S|F|P|\.]?", pd_command); - current_counter += 1; + if (inbound_match is None): + updated_commands.append(pd_command); + return bytes("", "utf-8") - control = control_byte % 4; + try: + inst = decode_instruction(buf) + except: + return bytes("", "utf-8") - if control == 0: - (current_counter, inst) = generate_replace_tcp_inst(buf, current_counter); - elif control == 1: - (current_counter, inst) = generate_replace_ip_inst(buf, current_counter); - elif control == 2: - (current_counter, inst) = generate_insert_inst(buf, current_counter); - else: - (current_counter, inst) = generate_truncate_tcp_header_inst(buf, current_counter); + if (inst == ""): + return bytes("", "utf-8") + else: + print(f"Fuzz Instruction: {inst}") + 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 (inst == ""): - updated_commands.append(pd_command); - else: - 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()); + # timestamp = calendar.timegm(time.gmtime()); - mutated_filename = f"afl-pd-{timestamp}.pkt" + # mutated_filename = f"afl-pd-{timestamp}.pkt" - with open(mutated_filename, "wb") as mutated_files: - mutated_files.write(updated_buf); """ + # with open(mutated_filename, "wb") as mutated_files: + # mutated_files.write(updated_buf); - pd_command_string = ''.join(pd_commands); + # pd_command_string = ''.join(pd_commands); - return bytearray(updated_command_string.encode()); + return updated_buf; if __name__ == "__main__": From f6aecbda259e4f68617cad86b4f5b57b168d6791 Mon Sep 17 00:00:00 2001 From: AmPaschal Date: Mon, 27 Feb 2023 05:28:49 +0000 Subject: [PATCH 06/10] Invoke python postprocessor directly --- src/afl-fuzz-run.c | 94 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 14 deletions(-) diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 24ecd89a9d..fc566334ba 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -84,29 +84,78 @@ 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 = fopen("/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/original_fuzz_seed", "wb"); + fwrite(new_mem, 1, new_size, fp); + fclose(fp); - }); + // Call python script to postprocess + system("python3 /home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/example.py /home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/original_fuzz_seed /home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/"); + + // Read content of the postprocessed file to new_buf + FILE *fp2 = fopen("/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/original_fuzz_seed.pd", "r"); + fseek(fp2, 0, SEEK_END); + new_size = ftell(fp2); + fseek(fp2, 0, SEEK_SET); /* same as rewind(f); */ + new_buf = malloc(new_size); + fread(new_buf, new_size, 1, fp2); + fclose(fp2); + + 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)) { @@ -996,9 +1045,26 @@ 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; + } + + 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) { From 92cc089514deed3cf5bf40326860b636a87550fa Mon Sep 17 00:00:00 2001 From: AmPaschal Date: Tue, 28 Feb 2023 03:57:43 +0000 Subject: [PATCH 07/10] Updated post-processor to receive hex buffers + Added fuzzing seed encoder and decoder + Modified afl-fuzz-one to recognize metadata in fuzzing seed --- conf-fuzz-env.sh | 9 + custom_mutators/packetdrill/.gitignore | 3 + custom_mutators/packetdrill/example.py | 113 +++--- .../packetdrill/fuzz-instruction-decoder.py | 47 +++ .../packetdrill/fuzz-instruction-encoder.py | 54 +++ .../packetdrill/fuzz-udp-instructions.txt | 3 + .../packetdrill/fuzz_in_2_instructions.txt | 34 ++ .../fuzz-template-tcp-established-option.pkt | 10 + .../fuzz-template-tcp-established.pkt | 10 + .../templates/fuzz-template-tcp-fin-wait.pkt | 13 + .../templates/fuzz-template-tcp-last-ack.pkt | 11 + .../templates/fuzz-template-tcp-listen.pkt | 5 + .../templates/fuzz-template-tcp-send.pkt | 12 + .../templates/fuzz-template-tcp-syn-rcvd.pkt | 9 + .../templates/fuzz-template-tcp-syn-sent.pkt | 5 + .../fuzz_template_socket_closed.pkt | 3 + .../fuzz_template_socket_open.pkt | 7 + include/afl-fuzz.h | 3 + qemu_mode/qemuafl | 2 +- src/afl-forkserver.c | 56 ++- src/afl-fuzz-one.c | 14 +- src/afl-fuzz-run.c | 322 ++++++++++++++++++ unicorn_mode/unicornafl | 2 +- 23 files changed, 670 insertions(+), 77 deletions(-) create mode 100755 conf-fuzz-env.sh create mode 100644 custom_mutators/packetdrill/.gitignore create mode 100644 custom_mutators/packetdrill/fuzz-instruction-decoder.py create mode 100644 custom_mutators/packetdrill/fuzz-instruction-encoder.py create mode 100644 custom_mutators/packetdrill/fuzz-udp-instructions.txt create mode 100644 custom_mutators/packetdrill/fuzz_in_2_instructions.txt create mode 100644 custom_mutators/packetdrill/templates/fuzz-template-tcp-established-option.pkt create mode 100644 custom_mutators/packetdrill/templates/fuzz-template-tcp-established.pkt create mode 100644 custom_mutators/packetdrill/templates/fuzz-template-tcp-fin-wait.pkt create mode 100644 custom_mutators/packetdrill/templates/fuzz-template-tcp-last-ack.pkt create mode 100644 custom_mutators/packetdrill/templates/fuzz-template-tcp-listen.pkt create mode 100644 custom_mutators/packetdrill/templates/fuzz-template-tcp-send.pkt create mode 100644 custom_mutators/packetdrill/templates/fuzz-template-tcp-syn-rcvd.pkt create mode 100644 custom_mutators/packetdrill/templates/fuzz-template-tcp-syn-sent.pkt create mode 100644 custom_mutators/packetdrill/udp_templates/fuzz_template_socket_closed.pkt create mode 100644 custom_mutators/packetdrill/udp_templates/fuzz_template_socket_open.pkt 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..e93aa40837 --- /dev/null +++ b/custom_mutators/packetdrill/.gitignore @@ -0,0 +1,3 @@ +/fuzz_in +/fuzz_in_2 +/fuzz_udp_in \ No newline at end of file diff --git a/custom_mutators/packetdrill/example.py b/custom_mutators/packetdrill/example.py index af5d1cd64d..2ebd242248 100644 --- a/custom_mutators/packetdrill/example.py +++ b/custom_mutators/packetdrill/example.py @@ -21,9 +21,11 @@ import re import sys import os +import binascii iter_index = 0 +debug = 0 def init(seed): """ @@ -38,6 +40,10 @@ def init(seed): def deinit(): pass +def debug_print(msg): + if debug: + print(msg) + def get_pd_commands_from_script(filename): try: @@ -49,7 +55,7 @@ def get_pd_commands_from_script(filename): return pruned_commands; except: - print("Exception while opening the file"); + debug_print("Exception while opening the file"); return []; tcp_fields = [ @@ -171,7 +177,7 @@ def generate_insert_tcp_option(buf, current_counter): option_values = buf[current_counter: current_counter + option_len] current_counter += option_len - #print(f"option_kind: {option_kind} \n option_len: {option_len} \n option_values: {option_values}") + #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) @@ -193,7 +199,7 @@ def generate_insert_IPv4_option(buf, current_counter): option_len_value = option_len + 2 - #print(f"option_kind: {option_kind} \n option_len: {option_len_value} \n option_values: {option_values}") + #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) @@ -237,17 +243,26 @@ def generate_delete_inst(buf, current_counter): ] opcodes = [ - (0, "INSERT_MSS", "ins tcp mss", True), - (1, "INSERT_IP_OPTION", "ins ipv4 20", True), - (2, "REPLACE_IPV4_HEADER_LENGTH", "rep ipv4 version_ihl", True), - (3, "REPLACE_TCP_HEADER_LENGTH", "rep tcp tcp_hdr_len", True), - (4, "TRUN_TCP_HEADER", "trun tcp 0", False), - (5, "REPLACE_IPV4_SOURCE_ADDR", "rep ipv4 src_ip", True) - ] +(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}") + debug_print(f"opcode {opcode}") opcode_found = False for i, op in enumerate(opcodes): if op[0] == opcode: @@ -261,7 +276,7 @@ def decode_instruction(bytes_: bytes): if op[3] == True: value = bytes_[4:].hex().upper() if len(value) == 0: - print(f"invalid value: {bytes_.hex().upper()}") + debug_print(f"invalid value: {bytes_.hex().upper()}") return "" fuzz_inst = "{" + op[2] + " " + "0x"+value + "}" else: @@ -288,7 +303,7 @@ def post_process(buf): if (len(buf) < 4): return bytes("", "utf-8"); - # print(f"Fuzz iteration {iter_index}") + # debug_print(f"Fuzz iteration {iter_index}") state_idx_to_fuzz = buf[1] % len(tcp_states) @@ -297,8 +312,8 @@ def post_process(buf): pd_commands = get_pd_commands_from_script(state_to_fuzz[1]); - print(f"STate to fuzz: {state_to_fuzz}") - # print(f"Length of list: {len(pd_commands)}") + 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 @@ -321,8 +336,8 @@ def post_process(buf): if (inst == ""): return bytes("", "utf-8") else: - print(f"Fuzz Instruction: {inst}") - print(f"Script id: {state_idx_to_fuzz} min_length: {buf[2]} max_length: {buf[3]}") + 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); @@ -347,20 +362,32 @@ def post_process(buf): if __name__ == "__main__": - # Check if the user has provided two file paths - if len(sys.argv) != 3: - # If not, display an error message and exit - print("Error: please provide two file paths") - exit(1) + # 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] - # 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() - # 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) @@ -368,21 +395,29 @@ def post_process(buf): print("Post process retuned empty string") exit(1) - file_name = os.path.basename(src_path) - dest_file_name = os.path.join(dest_folder_path, file_name + ".pd") + 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")) + - # 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 - print(f"Successfully written post-processed data to {dest_file_name}") """ buf = b"042af4" current_counter, inst = generate_truncate_tcp_header_inst(buf, 0) - print(f"current counter: {current_counter}") - print("instruction: " + inst) """ + 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..ef59839179 --- /dev/null +++ b/custom_mutators/packetdrill/fuzz-instruction-decoder.py @@ -0,0 +1,47 @@ +import struct + +opcodes = [ + (0, "INSERT_MSS", "ins tcp mss", True), + (1, "INSERT_IP_OPTION", "ins ipv4 20", True), + (2, "REPLACE_IPV4_HEADER_LENGTH", "rep ipv4 version_ihl", True), + (3, "REPLACE_TCP_HEADER_LENGTH", "rep tcp tcp_hdr_len", True), + (4, "TRUN_TCP_HEADER", "trun tcp 0", False) + ] + +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/FreeRTOS/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Echo_Posix/out/default/crashes/id:000000,sig:11,src:000029,time:2034927,execs:2114,op:havoc,rep:4", "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..cdbb79c61d --- /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-instructions.txt", "r") as f: + instructions = f.readlines() + + for instruction in instructions: + with open("/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/fuzz_in_2/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/templates/fuzz-template-tcp-established-option.pkt b/custom_mutators/packetdrill/templates/fuzz-template-tcp-established-option.pkt new file mode 100644 index 0000000000..a070712e65 --- /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:2(1) 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..ab341ee473 --- /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:2(1) 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-fin-wait.pkt b/custom_mutators/packetdrill/templates/fuzz-template-tcp-fin-wait.pkt new file mode 100644 index 0000000000..b78cb640ea --- /dev/null +++ b/custom_mutators/packetdrill/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/templates/fuzz-template-tcp-last-ack.pkt b/custom_mutators/packetdrill/templates/fuzz-template-tcp-last-ack.pkt new file mode 100644 index 0000000000..c3e308b3e7 --- /dev/null +++ b/custom_mutators/packetdrill/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/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/templates/fuzz-template-tcp-send.pkt b/custom_mutators/packetdrill/templates/fuzz-template-tcp-send.pkt new file mode 100644 index 0000000000..11b4b9fdf3 --- /dev/null +++ b/custom_mutators/packetdrill/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, ..., 600) = 600 + +.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/templates/fuzz-template-tcp-syn-rcvd.pkt b/custom_mutators/packetdrill/templates/fuzz-template-tcp-syn-rcvd.pkt new file mode 100644 index 0000000000..bc7603bde8 --- /dev/null +++ b/custom_mutators/packetdrill/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/templates/fuzz-template-tcp-syn-sent.pkt b/custom_mutators/packetdrill/templates/fuzz-template-tcp-syn-sent.pkt new file mode 100644 index 0000000000..49625612db --- /dev/null +++ b/custom_mutators/packetdrill/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/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..77db752d0d 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; 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-forkserver.c b/src/afl-forkserver.c index fa330a9a54..beea00e6b5 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -1093,7 +1093,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, char tun_name[6]; /* Connect to the device */ - strcpy(tun_name, "tap0"); + strcpy(tun_name, "tap1"); int tun_fd = tun_alloc(tun_name, IFF_TAP | IFF_NO_PI); /* tun interface */ if(tun_fd < 0){ @@ -1694,11 +1694,11 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, if (pd_pid==0) { /* child process */ /* open /dev/null for writing */ - // int fd = open("/dev/null", O_WRONLY); + 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 */ + 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 */ @@ -1709,9 +1709,24 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, "--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}; @@ -1730,36 +1745,6 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, exit(127); /* only if execv fails */ } - /* - pid_t pd_pid = fork(); - if (pd_pid==0) { - - pd_pid = fork(); - - if (pd_pid == 0) { - - 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", - "--non_fatal=packet", - "--tolerance_usecs=1000000", pd_script, NULL}; - 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); - } else { - // Send the pid to parent - exit(0); - } - - - } - */ - fsrv->pd_pid = pd_pid; restart_read: @@ -1773,6 +1758,7 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, 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; diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index ed9e7a81db..67797663a0 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"); } @@ -534,6 +539,12 @@ 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; + /********************* * PERFORMANCE SCORE * @@ -3119,7 +3130,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; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index fc566334ba..a7d1243996 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -69,6 +69,328 @@ 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. 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 From f0218faf1fcecaf52fc2bc21c0d84a1252f17b2f Mon Sep 17 00:00:00 2001 From: AmPaschal Date: Tue, 7 Mar 2023 12:34:09 +0000 Subject: [PATCH 08/10] Added fuzz templates + Updated postprocessor implementation --- custom_mutators/packetdrill/.gitignore | 3 +- custom_mutators/packetdrill/example.py | 2 +- .../packetdrill/fuzz-instruction-decoder.py | 24 +- .../packetdrill/fuzz-instruction-encoder.py | 4 +- .../packetdrill/fuzz_in_vuln_instructions.txt | 4 + .../fuzz_in_vuln_instructions_2.txt | 1 + .../fuzz-template-tcp-fin-wait.pkt | 0 .../fuzz-template-tcp-last-ack.pkt | 0 .../fuzz-template-tcp-send.pkt | 2 +- .../fuzz-template-tcp-syn-rcvd.pkt | 0 .../fuzz-template-tcp-syn-sent.pkt | 0 .../fuzz-template-tcp-established-option.pkt | 2 +- .../fuzz-template-tcp-established.pkt | 2 +- include/afl-fuzz.h | 7 + src/afl-forkserver.c | 30 +- src/afl-fuzz-one.c | 1447 ++--------------- src/afl-fuzz-run.c | 54 +- src/afl-fuzz.c | 79 + 18 files changed, 342 insertions(+), 1319 deletions(-) create mode 100644 custom_mutators/packetdrill/fuzz_in_vuln_instructions.txt create mode 100644 custom_mutators/packetdrill/fuzz_in_vuln_instructions_2.txt rename custom_mutators/packetdrill/{templates => templates-res}/fuzz-template-tcp-fin-wait.pkt (100%) rename custom_mutators/packetdrill/{templates => templates-res}/fuzz-template-tcp-last-ack.pkt (100%) rename custom_mutators/packetdrill/{templates => templates-res}/fuzz-template-tcp-send.pkt (93%) rename custom_mutators/packetdrill/{templates => templates-res}/fuzz-template-tcp-syn-rcvd.pkt (100%) rename custom_mutators/packetdrill/{templates => templates-res}/fuzz-template-tcp-syn-sent.pkt (100%) diff --git a/custom_mutators/packetdrill/.gitignore b/custom_mutators/packetdrill/.gitignore index e93aa40837..43d47950b1 100644 --- a/custom_mutators/packetdrill/.gitignore +++ b/custom_mutators/packetdrill/.gitignore @@ -1,3 +1,2 @@ -/fuzz_in -/fuzz_in_2 +/fuzz_in*/ /fuzz_udp_in \ No newline at end of file diff --git a/custom_mutators/packetdrill/example.py b/custom_mutators/packetdrill/example.py index 2ebd242248..56ec9d91bd 100644 --- a/custom_mutators/packetdrill/example.py +++ b/custom_mutators/packetdrill/example.py @@ -317,7 +317,7 @@ def post_process(buf): fuzz_index = state_to_fuzz[2] - 1 - pd_command = pd_commands[fuzz_index] + pd_command = pd_commands[fuzz_index] # Possible list index out of bounds #updated_commands = pd_commands[:-1] updated_commands = pd_commands[0: fuzz_index] diff --git a/custom_mutators/packetdrill/fuzz-instruction-decoder.py b/custom_mutators/packetdrill/fuzz-instruction-decoder.py index ef59839179..68b089e1b8 100644 --- a/custom_mutators/packetdrill/fuzz-instruction-decoder.py +++ b/custom_mutators/packetdrill/fuzz-instruction-decoder.py @@ -1,12 +1,22 @@ import struct opcodes = [ - (0, "INSERT_MSS", "ins tcp mss", True), - (1, "INSERT_IP_OPTION", "ins ipv4 20", True), - (2, "REPLACE_IPV4_HEADER_LENGTH", "rep ipv4 version_ihl", True), - (3, "REPLACE_TCP_HEADER_LENGTH", "rep tcp tcp_hdr_len", True), - (4, "TRUN_TCP_HEADER", "trun tcp 0", False) - ] +(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) @@ -32,7 +42,7 @@ def decode_instruction(bytes_: bytes): return fuzz_inst def main(): - with open("/home/pamusuo/research/rtos-fuzzing/FreeRTOS/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Echo_Posix/out/default/crashes/id:000000,sig:11,src:000029,time:2034927,execs:2114,op:havoc,rep:4", "rb") as f: + 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_) diff --git a/custom_mutators/packetdrill/fuzz-instruction-encoder.py b/custom_mutators/packetdrill/fuzz-instruction-encoder.py index cdbb79c61d..d076b0da14 100644 --- a/custom_mutators/packetdrill/fuzz-instruction-encoder.py +++ b/custom_mutators/packetdrill/fuzz-instruction-encoder.py @@ -42,11 +42,11 @@ def translate_instruction(instruction: str): 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-instructions.txt", "r") as f: + 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_2/instruction_"+str(instructions.index(instruction))+".bin", "wb") as f: + 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_) 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/templates/fuzz-template-tcp-fin-wait.pkt b/custom_mutators/packetdrill/templates-res/fuzz-template-tcp-fin-wait.pkt similarity index 100% rename from custom_mutators/packetdrill/templates/fuzz-template-tcp-fin-wait.pkt rename to custom_mutators/packetdrill/templates-res/fuzz-template-tcp-fin-wait.pkt diff --git a/custom_mutators/packetdrill/templates/fuzz-template-tcp-last-ack.pkt b/custom_mutators/packetdrill/templates-res/fuzz-template-tcp-last-ack.pkt similarity index 100% rename from custom_mutators/packetdrill/templates/fuzz-template-tcp-last-ack.pkt rename to custom_mutators/packetdrill/templates-res/fuzz-template-tcp-last-ack.pkt diff --git a/custom_mutators/packetdrill/templates/fuzz-template-tcp-send.pkt b/custom_mutators/packetdrill/templates-res/fuzz-template-tcp-send.pkt similarity index 93% rename from custom_mutators/packetdrill/templates/fuzz-template-tcp-send.pkt rename to custom_mutators/packetdrill/templates-res/fuzz-template-tcp-send.pkt index 11b4b9fdf3..54615bbeff 100644 --- a/custom_mutators/packetdrill/templates/fuzz-template-tcp-send.pkt +++ b/custom_mutators/packetdrill/templates-res/fuzz-template-tcp-send.pkt @@ -7,6 +7,6 @@ +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, ..., 600) = 600 + +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/templates/fuzz-template-tcp-syn-rcvd.pkt b/custom_mutators/packetdrill/templates-res/fuzz-template-tcp-syn-rcvd.pkt similarity index 100% rename from custom_mutators/packetdrill/templates/fuzz-template-tcp-syn-rcvd.pkt rename to custom_mutators/packetdrill/templates-res/fuzz-template-tcp-syn-rcvd.pkt diff --git a/custom_mutators/packetdrill/templates/fuzz-template-tcp-syn-sent.pkt b/custom_mutators/packetdrill/templates-res/fuzz-template-tcp-syn-sent.pkt similarity index 100% rename from custom_mutators/packetdrill/templates/fuzz-template-tcp-syn-sent.pkt rename to custom_mutators/packetdrill/templates-res/fuzz-template-tcp-syn-sent.pkt diff --git a/custom_mutators/packetdrill/templates/fuzz-template-tcp-established-option.pkt b/custom_mutators/packetdrill/templates/fuzz-template-tcp-established-option.pkt index a070712e65..59be80e73d 100644 --- a/custom_mutators/packetdrill/templates/fuzz-template-tcp-established-option.pkt +++ b/custom_mutators/packetdrill/templates/fuzz-template-tcp-established-option.pkt @@ -6,5 +6,5 @@ +.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:2(1) 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 index ab341ee473..9c542dd03c 100644 --- a/custom_mutators/packetdrill/templates/fuzz-template-tcp-established.pkt +++ b/custom_mutators/packetdrill/templates/fuzz-template-tcp-established.pkt @@ -6,5 +6,5 @@ +.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:2(1) 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/include/afl-fuzz.h b/include/afl-fuzz.h index 77db752d0d..90e0fc807f 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -762,6 +762,13 @@ 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; + #ifdef INTROSPECTION char mutation[8072]; char m_tmp[4096]; diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index beea00e6b5..65c614d1bb 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -814,6 +814,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() @@ -1090,17 +1106,25 @@ 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 - char tun_name[6]; + const char *interface_name = getenv("TAP_INTERFACE_NAME"); + + if (interface_name == NULL || strlen(interface_name) >= IFNAMSIZ) { + interface_name = "tap1"; + } + + char tun_name[strlen(interface_name) + 1]; /* Connect to the device */ - strcpy(tun_name, "tap1"); + strncpy(tun_name, interface_name, strlen(interface_name)); + tun_name[strlen(interface_name)] = '\0'; + int tun_fd = tun_alloc(tun_name, IFF_TAP | 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 succeeded with fd %d\n", tun_fd); + printf("Allocating tap interface %s succeeded with fd %d\n", tun_name, tun_fd); fsrv->pd_tap_fd = tun_fd; } } diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 67797663a0..35916f0afa 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -539,11 +539,13 @@ 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; /********************* @@ -976,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; } @@ -1109,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. */ + + for (i = 0; i < (u32)len; ++i) { - u16 orig = *(u16 *)(out_buf + 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; } @@ -1236,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 @@ -1296,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; @@ -1315,471 +1213,76 @@ u8 fuzz_one_original(afl_state_t *afl) { } - /* Big endian next. */ - - afl->stage_val_type = STAGE_VAL_BE; + } - if ((SWAP32(orig) & 0xffff) + j > 0xffff && !could_be_bitflip(r3)) { + *(u16 *)(out_buf + i) = orig; - afl->stage_cur_val = j; - *(u32 *)(out_buf + i) = SWAP32(SWAP32(orig) + j); + } -#ifdef INTROSPECTION - snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH32+BE-%u-%u", - afl->queue_cur->fname, i, j); -#endif + new_hit_cnt = afl->queued_items + afl->saved_crashes; - if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } - ++afl->stage_cur; + afl->stage_finds[STAGE_INTEREST16] += new_hit_cnt - orig_hit_cnt; + afl->stage_cycles[STAGE_INTEREST16] += afl->stage_max; - } else { + if (len < 4) { goto skip_interest; } - --afl->stage_max; - } - if ((SWAP32(orig) & 0xffff) < (u32)j && !could_be_bitflip(r4)) { +skip_interest: - afl->stage_cur_val = -j; - *(u32 *)(out_buf + i) = SWAP32(SWAP32(orig) - j); + /******************** + * DICTIONARY STUFF * + ********************/ -#ifdef INTROSPECTION - snprintf(afl->mutation, sizeof(afl->mutation), "%s ARITH32_BE-%u-%u", - afl->queue_cur->fname, i, j); -#endif + if (!afl->extras_cnt) { goto skip_user_extras; } - if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } - ++afl->stage_cur; + /* Overwrite with user-supplied extras. */ - } else { + afl->stage_name = "user extras (over)"; + afl->stage_short = "ext_UO"; + afl->stage_cur = 0; + afl->stage_max = afl->extras_cnt * len; - --afl->stage_max; + afl->stage_val_type = STAGE_VAL_NONE; - } + orig_hit_cnt = new_hit_cnt; - *(u32 *)(out_buf + i) = orig; + for (i = 0; i < (u32)len; ++i) { - } + u32 last_len = 0; - } + afl->stage_cur_byte = i; - 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) { - - 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. */ - u32 min_extra_len = MIN(afl->a_extras_cnt, (u32)USE_AUTO_EXTRAS); - for (j = 0; j < min_extra_len; ++j) { + for (j = 0; j < afl->extras_cnt; ++j) { - /* See the comment in the earlier code; extras are sorted by size. */ + /* 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->a_extras[j].len > len - i || - !memcmp(afl->a_extras[j].data, out_buf + i, afl->a_extras[j].len) || + 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; } @@ -1789,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: @@ -1981,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); } @@ -2083,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)); @@ -2141,294 +1575,104 @@ u8 fuzz_one_original(afl_state_t *afl) { } - } - - } - - }); - - } - - 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. */ + switch ((r = rand_below(afl, r_max))) { - if (temp_len < 2) { break; } + 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 @@ -2443,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. */ @@ -2575,7 +1710,7 @@ u8 fuzz_one_original(afl_state_t *afl) { } - case 52: { + case 20: { /* Increase byte by 1. */ @@ -2588,7 +1723,7 @@ u8 fuzz_one_original(afl_state_t *afl) { } - case 53: { + case 21: { /* Decrease byte by 1. */ @@ -2601,7 +1736,7 @@ u8 fuzz_one_original(afl_state_t *afl) { } - case 54: { + case 22: { /* Flip byte. */ @@ -2614,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); @@ -2753,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 @@ -2902,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. */ @@ -2957,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; @@ -3206,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 * @@ -4324,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 */ @@ -4439,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 */ @@ -5264,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. */ @@ -5407,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 a7d1243996..03fd22ff87 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -424,21 +424,62 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) { // Write new_mem to file - FILE *fp = fopen("/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/original_fuzz_seed", "wb"); + FILE *fp = (FILE *) afl->file_in; + if (ftruncate(fp->_fileno, 0) == -1) { + // handle error + printf("Truncating in file failed with errno %d...\n", errno); + return 0; + } + fseek(fp, 0, SEEK_SET); fwrite(new_mem, 1, new_size, fp); - fclose(fp); + // fclose(fp); + + // memcpy(afl->mmap_in, new_mem, new_size); + + // 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/"; - // Call python script to postprocess - system("python3 /home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/example.py /home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/original_fuzz_seed /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 *fp2 = fopen("/home/pamusuo/research/rtos-fuzzing/AFLplusplus/custom_mutators/packetdrill/original_fuzz_seed.pd", "r"); + FILE *fp2 = (FILE *) afl->file_out; fseek(fp2, 0, SEEK_END); new_size = ftell(fp2); fseek(fp2, 0, SEEK_SET); /* same as rewind(f); */ new_buf = malloc(new_size); fread(new_buf, new_size, 1, fp2); - fclose(fp2); + + if (ftruncate(fp2->_fileno, 0) == -1) { + // handle error + printf("Truncating out file failed...\n"); + return 0; + } + // 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)) { @@ -1375,6 +1416,7 @@ 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) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 294c42f6bb..d9f2f64105 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -381,6 +381,83 @@ static int stricmp(char const *a, char const *b) { } +const int SIZE = 4096; + +void afl_mmap_deinit(afl_state_t *afl) { + /* Close file pointers used for post-processor IO */ + + munmap(afl->mmap_in, SIZE); + munmap(afl->mmap_out, SIZE); + + fclose((FILE *) afl->file_in); + fclose((FILE *) afl->file_out); +} + +void afl_mmap_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); + } + + FILE *fp_in = fopen(seed_file, "wb+"); + + if (fp_in == NULL) { + printf("Error initializing post-processor input...\n"); + exit(-1); + } + + // void *ptr_in = mmap(NULL, SIZE, PROT_WRITE, MAP_SHARED, fp_in->_fileno, 0); + + // if (ptr_in == MAP_FAILED) { + // printf("mmap_in failed with error %d\n", errno); + // exit(1); + // } else { + // printf("Mmap in completed...\n"); + // } + + 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"); + + FILE *fp_out = fopen(pd_script_file, "w+"); + + if (fp_out == NULL) { + printf("Error initializing post-processor output...\n"); + exit(-1); + } + + // void *ptr_out = mmap(NULL, SIZE, PROT_READ, MAP_SHARED, fp_out->_fileno, 0); + + // if (ptr_out == MAP_FAILED) { + // printf("mmap_out failed with error %d\n", errno); + // exit(1); + // } else { + // printf("Mmap out completed...\n"); + // } + + // memset(ptr_in, 0, SIZE - 1); + // memset(ptr_out, 0, SIZE - 1); + + afl->file_in = (u8 *) fp_in; + afl->file_out = (u8 *) fp_out; + afl->seed_file = seed_file; + + // afl->mmap_in = (u8 *) ptr_in; + // afl->mmap_out = (u8 *) ptr_out; + + // printf("Mmap completed...\n"); + +} + static void fasan_check_afl_preload(char *afl_preload) { char first_preload[PATH_MAX + 1] = {0}; @@ -528,6 +605,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_mmap_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 +2719,7 @@ int main(int argc, char **argv_orig, char **envp) { } afl_fsrv_deinit(&afl->fsrv); + afl_mmap_deinit(afl); /* remove tmpfile */ if (afl->tmp_dir != NULL && !afl->in_place_resume && afl->fsrv.out_file) { From 583fbbdb878d01b10819a6ad416a8d350e628b1a Mon Sep 17 00:00:00 2001 From: AmPaschal Date: Tue, 7 Mar 2023 12:39:36 +0000 Subject: [PATCH 09/10] Changed comment --- src/afl-forkserver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 65c614d1bb..06ebf473d9 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -76,7 +76,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) { From 5363f772be49a7f449a6c79b64c9a9a3693b0a96 Mon Sep 17 00:00:00 2001 From: AmPaschal Date: Fri, 10 Mar 2023 01:43:04 +0000 Subject: [PATCH 10/10] Modified how postprocessor File IO is handled --- .../fuzz-template-tcp-established-option.pkt | 10 ++++ .../fuzz-template-tcp-established.pkt | 10 ++++ .../fuzz-template-tcp-fin-wait.pkt | 0 .../fuzz-template-tcp-last-ack.pkt | 2 +- .../fuzz-template-tcp-listen.pkt | 5 ++ .../fuzz-template-tcp-send.pkt | 0 .../fuzz-template-tcp-syn-rcvd.pkt | 0 .../fuzz-template-tcp-syn-sent.pkt | 0 include/afl-fuzz.h | 1 + src/afl-forkserver.c | 10 +++- src/afl-fuzz-run.c | 36 +++++------- src/afl-fuzz.c | 58 +++---------------- 12 files changed, 59 insertions(+), 73 deletions(-) create mode 100644 custom_mutators/packetdrill/new_templates/fuzz-template-tcp-established-option.pkt create mode 100644 custom_mutators/packetdrill/new_templates/fuzz-template-tcp-established.pkt rename custom_mutators/packetdrill/{templates-res => new_templates}/fuzz-template-tcp-fin-wait.pkt (100%) rename custom_mutators/packetdrill/{templates-res => new_templates}/fuzz-template-tcp-last-ack.pkt (92%) create mode 100644 custom_mutators/packetdrill/new_templates/fuzz-template-tcp-listen.pkt rename custom_mutators/packetdrill/{templates-res => new_templates}/fuzz-template-tcp-send.pkt (100%) rename custom_mutators/packetdrill/{templates-res => new_templates}/fuzz-template-tcp-syn-rcvd.pkt (100%) rename custom_mutators/packetdrill/{templates-res => new_templates}/fuzz-template-tcp-syn-sent.pkt (100%) 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/templates-res/fuzz-template-tcp-fin-wait.pkt b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-fin-wait.pkt similarity index 100% rename from custom_mutators/packetdrill/templates-res/fuzz-template-tcp-fin-wait.pkt rename to custom_mutators/packetdrill/new_templates/fuzz-template-tcp-fin-wait.pkt diff --git a/custom_mutators/packetdrill/templates-res/fuzz-template-tcp-last-ack.pkt b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-last-ack.pkt similarity index 92% rename from custom_mutators/packetdrill/templates-res/fuzz-template-tcp-last-ack.pkt rename to custom_mutators/packetdrill/new_templates/fuzz-template-tcp-last-ack.pkt index c3e308b3e7..86b238d536 100644 --- a/custom_mutators/packetdrill/templates-res/fuzz-template-tcp-last-ack.pkt +++ b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-last-ack.pkt @@ -8,4 +8,4 @@ +.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 + +.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/templates-res/fuzz-template-tcp-send.pkt b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-send.pkt similarity index 100% rename from custom_mutators/packetdrill/templates-res/fuzz-template-tcp-send.pkt rename to custom_mutators/packetdrill/new_templates/fuzz-template-tcp-send.pkt diff --git a/custom_mutators/packetdrill/templates-res/fuzz-template-tcp-syn-rcvd.pkt b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-syn-rcvd.pkt similarity index 100% rename from custom_mutators/packetdrill/templates-res/fuzz-template-tcp-syn-rcvd.pkt rename to custom_mutators/packetdrill/new_templates/fuzz-template-tcp-syn-rcvd.pkt diff --git a/custom_mutators/packetdrill/templates-res/fuzz-template-tcp-syn-sent.pkt b/custom_mutators/packetdrill/new_templates/fuzz-template-tcp-syn-sent.pkt similarity index 100% rename from custom_mutators/packetdrill/templates-res/fuzz-template-tcp-syn-sent.pkt rename to custom_mutators/packetdrill/new_templates/fuzz-template-tcp-syn-sent.pkt diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 90e0fc807f..5ea5da6511 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -768,6 +768,7 @@ typedef struct afl_state { u8 *mmap_in; u8 *mmap_out; char *seed_file; + char *pd_script_file; #ifdef INTROSPECTION char mutation[8072]; diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 06ebf473d9..364e4c84dc 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -54,6 +54,11 @@ #include #include +#define TAP 1 +#define TUN 2 + +#define CONFIG_NET_INTERFACE TAP + /** * The correct fds for reading and writing pipes */ @@ -1109,7 +1114,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, const char *interface_name = getenv("TAP_INTERFACE_NAME"); if (interface_name == NULL || strlen(interface_name) >= IFNAMSIZ) { - interface_name = "tap1"; + interface_name = CONFIG_NET_INTERFACE == TAP ? "tap1" : "tun0"; } char tun_name[strlen(interface_name) + 1]; @@ -1118,7 +1123,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, strncpy(tun_name, interface_name, strlen(interface_name)); tun_name[strlen(interface_name)] = '\0'; - int tun_fd = tun_alloc(tun_name, IFF_TAP | IFF_NO_PI); /* tun interface */ + 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); diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 03fd22ff87..1ea57cf86a 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -422,19 +422,19 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) { } + // Write new_mem to file - FILE *fp = (FILE *) afl->file_in; - if (ftruncate(fp->_fileno, 0) == -1) { - // handle error - printf("Truncating in file failed with errno %d...\n", errno); - return 0; - } - fseek(fp, 0, SEEK_SET); - fwrite(new_mem, 1, new_size, fp); - // fclose(fp); + - // memcpy(afl->mmap_in, new_mem, new_size); + 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"; @@ -448,18 +448,14 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) { system(cmd); // Read content of the postprocessed file to new_buf - FILE *fp2 = (FILE *) afl->file_out; - fseek(fp2, 0, SEEK_END); - new_size = ftell(fp2); - fseek(fp2, 0, SEEK_SET); /* same as rewind(f); */ + 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, fp2); + fread(new_buf, new_size, 1, fp_out); + fclose(fp_out); - if (ftruncate(fp2->_fileno, 0) == -1) { - // handle error - printf("Truncating out file failed...\n"); - return 0; - } // fclose(fp2); // struct stat st; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index d9f2f64105..5ed6e60010 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -383,17 +383,14 @@ static int stricmp(char const *a, char const *b) { const int SIZE = 4096; -void afl_mmap_deinit(afl_state_t *afl) { - /* Close file pointers used for post-processor IO */ +void afl_pp_file_deinit(afl_state_t *afl) { + /* Free pointers to post-processor file names */ - munmap(afl->mmap_in, SIZE); - munmap(afl->mmap_out, SIZE); - - fclose((FILE *) afl->file_in); - fclose((FILE *) afl->file_out); + free(afl->seed_file); + free(afl->pd_script_file); } -void afl_mmap_init(afl_state_t *afl) { +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; @@ -408,54 +405,15 @@ void afl_mmap_init(afl_state_t *afl) { seed_file = strdup(seed_file_template); } - FILE *fp_in = fopen(seed_file, "wb+"); - - if (fp_in == NULL) { - printf("Error initializing post-processor input...\n"); - exit(-1); - } - - // void *ptr_in = mmap(NULL, SIZE, PROT_WRITE, MAP_SHARED, fp_in->_fileno, 0); - - // if (ptr_in == MAP_FAILED) { - // printf("mmap_in failed with error %d\n", errno); - // exit(1); - // } else { - // printf("Mmap in completed...\n"); - // } 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"); - FILE *fp_out = fopen(pd_script_file, "w+"); - - if (fp_out == NULL) { - printf("Error initializing post-processor output...\n"); - exit(-1); - } - - // void *ptr_out = mmap(NULL, SIZE, PROT_READ, MAP_SHARED, fp_out->_fileno, 0); - - // if (ptr_out == MAP_FAILED) { - // printf("mmap_out failed with error %d\n", errno); - // exit(1); - // } else { - // printf("Mmap out completed...\n"); - // } - // memset(ptr_in, 0, SIZE - 1); - // memset(ptr_out, 0, SIZE - 1); - - afl->file_in = (u8 *) fp_in; - afl->file_out = (u8 *) fp_out; afl->seed_file = seed_file; + afl->pd_script_file = pd_script_file; - // afl->mmap_in = (u8 *) ptr_in; - // afl->mmap_out = (u8 *) ptr_out; - - // printf("Mmap completed...\n"); - } static void fasan_check_afl_preload(char *afl_preload) { @@ -605,7 +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_mmap_init(afl); + 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; @@ -2719,7 +2677,7 @@ int main(int argc, char **argv_orig, char **envp) { } afl_fsrv_deinit(&afl->fsrv); - afl_mmap_deinit(afl); + afl_pp_file_deinit(afl); /* remove tmpfile */ if (afl->tmp_dir != NULL && !afl->in_place_resume && afl->fsrv.out_file) {