aboutsummaryrefslogtreecommitdiff
path: root/frida_mode/src/instrument
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2021-08-27 17:06:46 +0200
committerGitHub <noreply@github.com>2021-08-27 17:06:46 +0200
commit353d402aaf9296c7dbd47e66fbbc6e59179c4e44 (patch)
tree0ba644854a6d51cdc9e8a2d52ca88b549109f736 /frida_mode/src/instrument
parent2e15661f184c77ac1fbb6f868c894e946cbb7f17 (diff)
parent7a2f81e0d992cf0f20d8d2fed26310c03c8b4fa9 (diff)
downloadafl++-353d402aaf9296c7dbd47e66fbbc6e59179c4e44.tar.gz
Merge pull request #1077 from AFLplusplus/dev
push to stable
Diffstat (limited to 'frida_mode/src/instrument')
-rw-r--r--frida_mode/src/instrument/instrument.c47
-rw-r--r--frida_mode/src/instrument/instrument_coverage.c723
2 files changed, 664 insertions, 106 deletions
diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c
index 9e4dd191..fd0982f8 100644
--- a/frida_mode/src/instrument/instrument.c
+++ b/frida_mode/src/instrument/instrument.c
@@ -29,14 +29,23 @@ guint64 instrument_hash_seed = 0;
gboolean instrument_use_fixed_seed = FALSE;
guint64 instrument_fixed_seed = 0;
+char * instrument_coverage_unstable_filename = NULL;
static GumStalkerTransformer *transformer = NULL;
__thread guint64 instrument_previous_pc = 0;
static GumAddress previous_rip = 0;
+static GumAddress previous_end = 0;
static u8 * edges_notified = NULL;
+typedef struct {
+
+ GumAddress address;
+ GumAddress end;
+
+} block_ctx_t;
+
static void trace_debug(char *format, ...) {
va_list ap;
@@ -91,9 +100,11 @@ __attribute__((hot)) static void on_basic_block(GumCpuContext *context,
UNUSED_PARAMETER(context);
- GumAddress current_rip = GUM_ADDRESS(user_data);
- guint64 current_pc = instrument_get_offset_hash(current_rip);
- guint64 edge;
+ block_ctx_t *ctx = (block_ctx_t *)user_data;
+ GumAddress current_rip = ctx->address;
+ guint16 current_end = ctx->end;
+ guint64 current_pc = instrument_get_offset_hash(current_rip);
+ guint64 edge;
edge = current_pc ^ instrument_previous_pc;
@@ -112,10 +123,18 @@ __attribute__((hot)) static void on_basic_block(GumCpuContext *context,
if (instrument_unique) { edges_notified[edge] = 1; }
- previous_rip = current_rip;
+ }
+
+ if (unlikely(instrument_coverage_unstable_filename != NULL)) {
+
+ instrument_coverage_unstable(edge, previous_rip, previous_end, current_rip,
+ current_end);
}
+ previous_rip = current_rip;
+ previous_end = current_end;
+
instrument_previous_pc = ((current_pc & (MAP_SIZE - 1) >> 1)) |
((current_pc & 0x1) << (MAP_SIZE_POW2 - 1));
@@ -130,6 +149,7 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
const cs_insn *instr;
gboolean begin = TRUE;
gboolean excluded;
+ block_ctx_t * ctx = NULL;
while (gum_stalker_iterator_next(iterator, &instr)) {
@@ -183,8 +203,9 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
} else {
- gum_stalker_iterator_put_callout(
- iterator, on_basic_block, GSIZE_TO_POINTER(instr->address), NULL);
+ ctx = gum_malloc0(sizeof(block_ctx_t));
+ ctx->address = GUM_ADDRESS(instr->address);
+ gum_stalker_iterator_put_callout(iterator, on_basic_block, ctx, NULL);
}
@@ -211,6 +232,8 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
}
+ if (ctx != NULL) { ctx->end = (instr->address + instr->size); }
+
instrument_flush(output);
instrument_debug_end(output);
instrument_coverage_end(instr->address + instr->size);
@@ -224,6 +247,8 @@ void instrument_config(void) {
instrument_unique = (getenv("AFL_FRIDA_INST_TRACE_UNIQUE") != NULL);
instrument_use_fixed_seed = (getenv("AFL_FRIDA_INST_SEED") != NULL);
instrument_fixed_seed = util_read_num("AFL_FRIDA_INST_SEED");
+ instrument_coverage_unstable_filename =
+ (getenv("AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE"));
instrument_debug_config();
instrument_coverage_config();
@@ -241,6 +266,9 @@ void instrument_init(void) {
OKF("Instrumentation - unique [%c]", instrument_unique ? 'X' : ' ');
OKF("Instrumentation - fixed seed [%c] [0x%016" G_GINT64_MODIFIER "x]",
instrument_use_fixed_seed ? 'X' : ' ', instrument_fixed_seed);
+ OKF("Instrumentation - unstable coverage [%c] [%s]",
+ instrument_coverage_unstable_filename == NULL ? ' ' : 'X',
+ instrument_coverage_unstable_filename);
if (instrument_tracing && instrument_optimize) {
@@ -249,6 +277,13 @@ void instrument_init(void) {
}
+ if (instrument_coverage_unstable_filename && instrument_optimize) {
+
+ WARNF("AFL_FRIDA_INST_COVERAGE_FILE implies AFL_FRIDA_INST_NO_OPTIMIZE");
+ instrument_optimize = FALSE;
+
+ }
+
if (instrument_unique && instrument_optimize) {
WARNF("AFL_FRIDA_INST_TRACE_UNIQUE implies AFL_FRIDA_INST_NO_OPTIMIZE");
diff --git a/frida_mode/src/instrument/instrument_coverage.c b/frida_mode/src/instrument/instrument_coverage.c
index 4c0d1a14..46c816bc 100644
--- a/frida_mode/src/instrument/instrument_coverage.c
+++ b/frida_mode/src/instrument/instrument_coverage.c
@@ -12,33 +12,52 @@
char *instrument_coverage_filename = NULL;
-static int coverage_fd = -1;
-static int coverage_pipes[2] = {0};
-static uint64_t coverage_last_start = 0;
-static GHashTable *coverage_hash = NULL;
-static GArray * coverage_modules = NULL;
-static guint coverage_marked_modules = 0;
-static guint coverage_marked_entries = 0;
+static int normal_coverage_fd = -1;
+static int normal_coverage_pipes[2] = {-1, -1};
+
+static int unstable_coverage_fd = -1;
+static int unstable_coverage_pipes[2] = {-1, -1};
+
+static uint64_t normal_coverage_last_start = 0;
+static gchar * unstable_coverage_fuzzer_stats = NULL;
typedef struct {
GumAddress base_address;
GumAddress limit;
gsize size;
- char name[PATH_MAX + 1];
char path[PATH_MAX + 1];
- bool referenced;
+ guint64 offset;
+ gboolean is_executable;
+ guint count;
guint16 id;
-} coverage_module_t;
+} coverage_range_t;
typedef struct {
- uint64_t start;
- uint64_t end;
- coverage_module_t *module;
+ uint64_t start;
+ uint64_t end;
+ coverage_range_t *module;
-} coverage_data_t;
+} normal_coverage_data_t;
+
+typedef struct {
+
+ guint64 edge;
+ guint64 from;
+ guint64 from_end;
+ guint64 to;
+ guint64 to_end;
+
+} unstable_coverage_data_t;
+
+typedef struct {
+
+ GArray *modules;
+ guint count;
+
+} coverage_mark_ctx_t;
typedef struct {
@@ -48,32 +67,44 @@ typedef struct {
} coverage_event_t;
-static gboolean coverage_module(const GumModuleDetails *details,
- gpointer user_data) {
+static gboolean coverage_range(const GumRangeDetails *details,
+ gpointer user_data) {
- UNUSED_PARAMETER(user_data);
- coverage_module_t coverage = {0};
+ GArray * coverage_ranges = (GArray *)user_data;
+ coverage_range_t coverage = {0};
+
+ if (details->file == NULL) { return TRUE; }
+ if (details->protection == GUM_PAGE_NO_ACCESS) { return TRUE; }
coverage.base_address = details->range->base_address;
coverage.size = details->range->size;
coverage.limit = coverage.base_address + coverage.size;
- if (details->name != NULL) strncpy(coverage.name, details->name, PATH_MAX);
+ strncpy(coverage.path, details->file->path, PATH_MAX);
+ coverage.offset = details->file->offset;
+
+ if ((details->protection & GUM_PAGE_EXECUTE) == 0) {
- if (details->path != NULL) strncpy(coverage.path, details->path, PATH_MAX);
+ coverage.is_executable = false;
+
+ } else {
+
+ coverage.is_executable = true;
+
+ }
- coverage.referenced = false;
+ coverage.count = 0;
coverage.id = 0;
- g_array_append_val(coverage_modules, coverage);
+ g_array_append_val(coverage_ranges, coverage);
return TRUE;
}
static gint coverage_sort(gconstpointer a, gconstpointer b) {
- coverage_module_t *ma = (coverage_module_t *)a;
- coverage_module_t *mb = (coverage_module_t *)b;
+ coverage_range_t *ma = (coverage_range_t *)a;
+ coverage_range_t *mb = (coverage_range_t *)b;
if (ma->base_address < mb->base_address) return -1;
@@ -83,52 +114,128 @@ static gint coverage_sort(gconstpointer a, gconstpointer b) {
}
-static void coverage_get_ranges(void) {
+void instrument_coverage_print(char *format, ...) {
+
+ char buffer[4096] = {0};
+ int len;
+
+ va_list ap;
+ va_start(ap, format);
+
+ if (vsnprintf(buffer, sizeof(buffer) - 1, format, ap) < 0) { return; }
+
+ len = strnlen(buffer, sizeof(buffer));
+ IGNORED_RETURN(write(STDOUT_FILENO, buffer, len));
+ va_end(ap);
+
+}
+
+static GArray *coverage_get_ranges(void) {
+
+ instrument_coverage_print("Coverage - Collecting ranges\n");
+
+ GArray *coverage_ranges =
+ g_array_sized_new(false, false, sizeof(coverage_range_t), 100);
+ gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, coverage_range,
+ coverage_ranges);
+ g_array_sort(coverage_ranges, coverage_sort);
+
+ for (guint i = 0; i < coverage_ranges->len; i++) {
+
+ coverage_range_t *range =
+ &g_array_index(coverage_ranges, coverage_range_t, i);
+ instrument_coverage_print("Coverage Range - %3u: 0x%016" G_GINT64_MODIFIER
+ "X - 0x%016" G_GINT64_MODIFIER "X (%s)\n",
+ i, range->base_address, range->limit,
+ range->path);
+
+ }
+
+ return coverage_ranges;
+
+}
+
+static GArray *coverage_get_modules(void) {
+
+ instrument_coverage_print("Coverage - Collecting modules\n");
+ GArray *coverage_ranges = coverage_get_ranges();
+ GArray *coverage_modules =
+ g_array_sized_new(false, false, sizeof(coverage_range_t), 100);
+
+ coverage_range_t current = {0};
+
+ for (guint i = 0; i < coverage_ranges->len; i++) {
+
+ coverage_range_t *range =
+ &g_array_index(coverage_ranges, coverage_range_t, i);
- OKF("Coverage - Collecting ranges");
+ if (range->offset == 0 ||
+ (strncmp(range->path, current.path, PATH_MAX) != 0)) {
- coverage_modules =
- g_array_sized_new(false, false, sizeof(coverage_module_t), 100);
- gum_process_enumerate_modules(coverage_module, NULL);
- g_array_sort(coverage_modules, coverage_sort);
+ if (current.is_executable) {
+
+ g_array_append_val(coverage_modules, current);
+ memset(&current, '\0', sizeof(coverage_range_t));
+
+ }
+
+ memcpy(&current, range, sizeof(coverage_range_t));
+
+ } else {
+
+ current.limit = range->limit;
+ current.size = current.limit - current.base_address;
+ if (range->is_executable) { current.is_executable = true; }
+
+ }
+
+ }
+
+ if (current.is_executable) { g_array_append_val(coverage_modules, current); }
+ g_array_free(coverage_ranges, TRUE);
for (guint i = 0; i < coverage_modules->len; i++) {
- coverage_module_t *module =
- &g_array_index(coverage_modules, coverage_module_t, i);
- OKF("Coverage Module - %3u: 0x%016" G_GINT64_MODIFIER
- "X - 0x%016" G_GINT64_MODIFIER "X",
- i, module->base_address, module->limit);
+ coverage_range_t *module =
+ &g_array_index(coverage_modules, coverage_range_t, i);
+ instrument_coverage_print("Coverage Module - %3u: 0x%016" G_GINT64_MODIFIER
+ "X - 0x%016" G_GINT64_MODIFIER "X (%s)\n",
+ i, module->base_address, module->limit,
+ module->path);
}
+ return coverage_modules;
+
}
static void instrument_coverage_mark(void *key, void *value, void *user_data) {
UNUSED_PARAMETER(key);
- UNUSED_PARAMETER(user_data);
- coverage_data_t *val = (coverage_data_t *)value;
- guint i;
+ coverage_mark_ctx_t * ctx = (coverage_mark_ctx_t *)user_data;
+ GArray * coverage_modules = ctx->modules;
+ normal_coverage_data_t *val = (normal_coverage_data_t *)value;
+ guint i;
for (i = 0; i < coverage_modules->len; i++) {
- coverage_module_t *module =
- &g_array_index(coverage_modules, coverage_module_t, i);
+ coverage_range_t *module =
+ &g_array_index(coverage_modules, coverage_range_t, i);
if (val->start > module->limit) continue;
if (val->end >= module->limit) break;
val->module = module;
- coverage_marked_entries++;
- module->referenced = true;
+ ctx->count = ctx->count + 1;
+ module->count++;
return;
}
- OKF("Coverage cannot find module for: 0x%016" G_GINT64_MODIFIER
- "X - 0x%016" G_GINT64_MODIFIER "X %u %u",
- val->start, val->end, i, coverage_modules->len);
+ instrument_coverage_print(
+ "Coverage cannot find module for: 0x%016" G_GINT64_MODIFIER
+ "X - 0x%016" G_GINT64_MODIFIER "X\n",
+ val->start, val->end);
}
@@ -140,7 +247,7 @@ static void coverage_write(void *data, size_t size) {
for (char *cursor = (char *)data; remain > 0;
remain -= written, cursor += written) {
- written = write(coverage_fd, cursor, remain);
+ written = write(normal_coverage_fd, cursor, remain);
if (written < 0) {
@@ -171,14 +278,14 @@ static void coverage_format(char *format, ...) {
}
-static void coverage_write_modules() {
+static void coverage_write_modules(GArray *coverage_modules) {
guint emitted = 0;
for (guint i = 0; i < coverage_modules->len; i++) {
- coverage_module_t *module =
- &g_array_index(coverage_modules, coverage_module_t, i);
- if (!module->referenced) continue;
+ coverage_range_t *module =
+ &g_array_index(coverage_modules, coverage_range_t, i);
+ if (module->count == 0) continue;
coverage_format("%3u, ", emitted);
coverage_format("%016" G_GINT64_MODIFIER "X, ", module->base_address);
@@ -200,7 +307,10 @@ static void coverage_write_events(void *key, void *value, void *user_data) {
UNUSED_PARAMETER(key);
UNUSED_PARAMETER(user_data);
- coverage_data_t *val = (coverage_data_t *)value;
+ normal_coverage_data_t *val = (normal_coverage_data_t *)value;
+
+ if (val->module == NULL) { return; }
+
coverage_event_t evt = {
.offset = val->start - val->module->base_address,
@@ -213,7 +323,7 @@ static void coverage_write_events(void *key, void *value, void *user_data) {
}
-static void coverage_write_header() {
+static void coverage_write_header(guint coverage_marked_modules) {
char version[] = "DRCOV VERSION: 2\n";
char flavour[] = "DRCOV FLAVOR: frida\n";
@@ -223,77 +333,321 @@ static void coverage_write_header() {
coverage_format("Module Table: version 2, count %u\n",
coverage_marked_modules);
coverage_write(columns, sizeof(columns) - 1);
- coverage_write_modules();
- coverage_format("BB Table: %u bbs\n", coverage_marked_entries);
- g_hash_table_foreach(coverage_hash, coverage_write_events, NULL);
}
-static void coverage_mark_modules() {
+static guint coverage_mark_modules(GArray *coverage_modules) {
+ guint coverage_marked_modules = 0;
guint i;
for (i = 0; i < coverage_modules->len; i++) {
- coverage_module_t *module =
- &g_array_index(coverage_modules, coverage_module_t, i);
+ coverage_range_t *module =
+ &g_array_index(coverage_modules, coverage_range_t, i);
- OKF("Coverage Module - %3u: [%c] 0x%016" G_GINT64_MODIFIER
- "X - 0x%016" G_GINT64_MODIFIER "X (%u:%s)",
- i, module->referenced ? 'X' : ' ', module->base_address, module->limit,
- module->id, module->path);
+ instrument_coverage_print(
+ "Coverage Module - %3u: [%c] 0x%016" G_GINT64_MODIFIER
+ "X - 0x%016" G_GINT64_MODIFIER "X [%u] (%u:%s)\n",
+ i, module->count == 0 ? ' ' : 'X', module->base_address, module->limit,
+ module->count, module->id, module->path);
- if (!module->referenced) { continue; }
+ if (module->count == 0) { continue; }
module->id = coverage_marked_modules;
coverage_marked_modules++;
}
+ return coverage_marked_modules;
+
}
-static void instrument_coverage_run() {
+static void instrument_coverage_normal_run() {
- int bytes;
- coverage_data_t data;
- coverage_data_t *value;
- OKF("Coverage - Running");
+ int bytes;
+ normal_coverage_data_t data;
+ normal_coverage_data_t *value;
+ instrument_coverage_print("Coverage - Running\n");
- if (close(coverage_pipes[STDOUT_FILENO]) != 0) {
+ if (close(normal_coverage_pipes[STDOUT_FILENO]) != 0) {
FATAL("Failed to close parent read pipe");
}
- for (bytes =
- read(coverage_pipes[STDIN_FILENO], &data, sizeof(coverage_data_t));
- bytes == sizeof(coverage_data_t);
- bytes =
- read(coverage_pipes[STDIN_FILENO], &data, sizeof(coverage_data_t))) {
+ GHashTable *coverage_hash =
+ g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
+ if (coverage_hash == NULL) {
+
+ FATAL("Failed to g_hash_table_new, errno: %d", errno);
+
+ }
+
+ for (bytes = read(normal_coverage_pipes[STDIN_FILENO], &data,
+ sizeof(normal_coverage_data_t));
+ bytes == sizeof(normal_coverage_data_t);
+ bytes = read(normal_coverage_pipes[STDIN_FILENO], &data,
+ sizeof(normal_coverage_data_t))) {
- value = (coverage_data_t *)gum_malloc0(sizeof(coverage_data_t));
- memcpy(value, &data, sizeof(coverage_data_t));
+ value =
+ (normal_coverage_data_t *)gum_malloc0(sizeof(normal_coverage_data_t));
+ memcpy(value, &data, sizeof(normal_coverage_data_t));
g_hash_table_insert(coverage_hash, GSIZE_TO_POINTER(data.start), value);
}
if (bytes != 0) { FATAL("Coverage data truncated"); }
- OKF("Coverage - Preparing");
+ instrument_coverage_print("Coverage - Preparing\n");
- coverage_get_ranges();
+ GArray *coverage_modules = coverage_get_modules();
guint size = g_hash_table_size(coverage_hash);
- OKF("Coverage - Total Entries: %u", size);
+ instrument_coverage_print("Coverage - Total Entries: %u\n", size);
+
+ coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0};
+
+ g_hash_table_foreach(coverage_hash, instrument_coverage_mark, &ctx);
+ instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count);
- g_hash_table_foreach(coverage_hash, instrument_coverage_mark, NULL);
- OKF("Coverage - Marked Entries: %u", coverage_marked_entries);
+ guint coverage_marked_modules = coverage_mark_modules(coverage_modules);
+ instrument_coverage_print("Coverage - Marked Modules: %u\n",
+ coverage_marked_modules);
- coverage_mark_modules();
- OKF("Coverage - Marked Modules: %u", coverage_marked_modules);
+ coverage_write_header(coverage_marked_modules);
+ coverage_write_modules(coverage_modules);
+ coverage_format("BB Table: %u bbs\n", ctx.count);
+ g_hash_table_foreach(coverage_hash, coverage_write_events, NULL);
+
+ g_hash_table_unref(coverage_hash);
+
+ instrument_coverage_print("Coverage - Completed\n");
+
+}
+
+static GArray *instrument_coverage_unstable_read_unstable_ids(void) {
+
+ gchar * contents = NULL;
+ gsize length = 0;
+ GArray *unstable_edge_ids =
+ g_array_sized_new(false, false, sizeof(gpointer), 100);
+
+ if (!g_file_get_contents(unstable_coverage_fuzzer_stats, &contents, &length,
+ NULL)) {
+
+ FATAL("Failed to read fuzzer_stats");
+
+ }
+
+ instrument_coverage_print("\n");
+ instrument_coverage_print("Unstable coverage stats:\n");
+ instrument_coverage_print("========================\n");
+ instrument_coverage_print("%s\n", contents);
+ instrument_coverage_print("\n");
+
+ gchar **lines = g_strsplit(contents, "\n", -1);
+ gchar **values = NULL;
+
+ for (guint i = 0; lines[i] != NULL; i++) {
+
+ gchar **fields = g_strsplit(lines[i], ":", 2);
+ if (fields[0] == NULL) {
+
+ g_strfreev(fields);
+ continue;
+
+ }
+
+ g_strstrip(fields[0]);
+ if (g_strcmp0(fields[0], "var_bytes") != 0) {
+
+ g_strfreev(fields);
+ continue;
+
+ }
+
+ if (fields[1] == NULL) {
+
+ g_strfreev(fields);
+ continue;
+
+ }
+
+ g_strstrip(fields[1]);
+ values = g_strsplit(fields[1], " ", -1);
+ g_strfreev(fields);
+
+ break;
+
+ }
+
+ if (values == NULL) {
+
+ instrument_coverage_print(
+ "Failed to find var_bytes, did you set AFL_DEBUG?\n");
+
+ }
+
+ for (guint i = 0; values[i] != NULL; i++) {
+
+ g_strstrip(values[i]);
+ gpointer val = GSIZE_TO_POINTER(g_ascii_strtoull(values[i], NULL, 10));
+ g_array_append_val(unstable_edge_ids, val);
+
+ }
- coverage_write_header();
+ g_strfreev(values);
+ g_strfreev(lines);
+ g_free(contents);
- OKF("Coverage - Completed");
+ for (guint i = 0; i < unstable_edge_ids->len; i++) {
+
+ gpointer *id = &g_array_index(unstable_edge_ids, gpointer, i);
+
+ instrument_coverage_print("Unstable edge (%10u): %" G_GINT64_MODIFIER "u\n",
+ i, GPOINTER_TO_SIZE(*id));
+
+ }
+
+ return unstable_edge_ids;
+
+}
+
+static GHashTable *instrument_collect_unstable_blocks(
+ GHashTable *unstable_coverage_hash, GArray *unstable_edge_ids) {
+
+ GHashTable *unstable_blocks =
+ g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
+
+ for (guint i = 0; i < unstable_edge_ids->len; i++) {
+
+ gpointer *id = &g_array_index(unstable_edge_ids, gpointer, i);
+
+ GHashTable *child =
+ (GHashTable *)g_hash_table_lookup(unstable_coverage_hash, *id);
+
+ if (child == NULL) { FATAL("Failed to find edge ID"); }
+
+ GHashTableIter iter = {0};
+ gpointer value;
+ g_hash_table_iter_init(&iter, child);
+ while (g_hash_table_iter_next(&iter, NULL, &value)) {
+
+ unstable_coverage_data_t *unstable = (unstable_coverage_data_t *)value;
+ normal_coverage_data_t * from =
+ gum_malloc0(sizeof(normal_coverage_data_t));
+ normal_coverage_data_t *to = gum_malloc0(sizeof(normal_coverage_data_t));
+ from->start = unstable->from;
+ from->end = unstable->from_end;
+ from->module = NULL;
+
+ to->start = unstable->to;
+ to->end = unstable->to_end;
+ to->module = NULL;
+
+ g_hash_table_insert(unstable_blocks, GSIZE_TO_POINTER(from->start), from);
+ g_hash_table_insert(unstable_blocks, GSIZE_TO_POINTER(to->start), to);
+
+ }
+
+ }
+
+ return unstable_blocks;
+
+}
+
+static void instrument_coverage_unstable_run(void) {
+
+ int bytes;
+ unstable_coverage_data_t data;
+ unstable_coverage_data_t *value;
+ instrument_coverage_print("Unstable coverage - Running\n");
+
+ if (close(unstable_coverage_pipes[STDOUT_FILENO]) != 0) {
+
+ FATAL("Failed to close parent read pipe");
+
+ }
+
+ GHashTable *unstable_coverage_hash = g_hash_table_new_full(
+ g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)g_hash_table_unref);
+ if (unstable_coverage_hash == NULL) {
+
+ FATAL("Failed to g_hash_table_new, errno: %d", errno);
+
+ }
+
+ guint edges = 0;
+
+ for (bytes = read(unstable_coverage_pipes[STDIN_FILENO], &data,
+ sizeof(unstable_coverage_data_t));
+ bytes == sizeof(unstable_coverage_data_t);
+ bytes = read(unstable_coverage_pipes[STDIN_FILENO], &data,
+ sizeof(unstable_coverage_data_t))) {
+
+ value = (unstable_coverage_data_t *)gum_malloc0(
+ sizeof(unstable_coverage_data_t));
+ memcpy(value, &data, sizeof(unstable_coverage_data_t));
+
+ gpointer hash_value = g_hash_table_lookup(unstable_coverage_hash,
+ GSIZE_TO_POINTER(value->edge));
+ if (hash_value == NULL) {
+
+ hash_value =
+ g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
+
+ if (!g_hash_table_insert(unstable_coverage_hash,
+ GSIZE_TO_POINTER(value->edge), hash_value)) {
+
+ FATAL("Entry already in hashtable");
+
+ }
+
+ }
+
+ if (g_hash_table_insert(hash_value, GSIZE_TO_POINTER(value->from), value)) {
+
+ edges++;
+
+ }
+
+ }
+
+ if (bytes != 0) { FATAL("Unstable coverage data truncated"); }
+
+ instrument_coverage_print("Coverage - Preparing\n");
+
+ GArray *coverage_modules = coverage_get_modules();
+
+ instrument_coverage_print("Found edges: %u\n", edges);
+
+ GArray *unstable_edge_ids = instrument_coverage_unstable_read_unstable_ids();
+
+ GHashTable *unstable_blocks = instrument_collect_unstable_blocks(
+ unstable_coverage_hash, unstable_edge_ids);
+
+ guint size = g_hash_table_size(unstable_blocks);
+ instrument_coverage_print("Unstable blocks: %u\n", size);
+
+ coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0};
+
+ g_hash_table_foreach(unstable_blocks, instrument_coverage_mark, &ctx);
+ instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count);
+
+ guint coverage_marked_modules = coverage_mark_modules(coverage_modules);
+ instrument_coverage_print("Coverage - Marked Modules: %u\n",
+ coverage_marked_modules);
+
+ coverage_write_header(coverage_marked_modules);
+ coverage_write_modules(coverage_modules);
+ coverage_format("BB Table: %u bbs\n", ctx.count);
+ g_hash_table_foreach(unstable_blocks, coverage_write_events, NULL);
+
+ g_hash_table_unref(unstable_blocks);
+ g_array_free(unstable_edge_ids, TRUE);
+ g_hash_table_unref(unstable_coverage_hash);
+
+ instrument_coverage_print("Coverage - Completed\n");
}
@@ -303,7 +657,7 @@ void instrument_coverage_config(void) {
}
-void instrument_coverage_init(void) {
+void instrument_coverage_normal_init(void) {
OKF("Coverage - enabled [%c]",
instrument_coverage_filename == NULL ? ' ' : 'X');
@@ -317,19 +671,147 @@ void instrument_coverage_init(void) {
OKF("Coverage - path [%s]", path);
- coverage_fd = open(path, O_RDWR | O_CREAT | O_TRUNC,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+ normal_coverage_fd = open(path, O_RDWR | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
- if (coverage_fd < 0) { FATAL("Failed to open coverage file '%s'", path); }
+ if (normal_coverage_fd < 0) {
+
+ FATAL("Failed to open coverage file '%s'", path);
+
+ }
g_free(path);
- if (pipe(coverage_pipes) != 0) { FATAL("Failed to create pipes"); }
+ if (pipe(normal_coverage_pipes) != 0) { FATAL("Failed to create pipes"); }
- coverage_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
- if (coverage_hash == NULL) {
+ pid_t pid = fork();
+ if (pid == -1) { FATAL("Failed to start coverage process"); }
- FATAL("Failed to g_hash_table_new, errno: %d", errno);
+ if (pid == 0) {
+
+ instrument_coverage_normal_run();
+ kill(getpid(), SIGKILL);
+ _exit(0);
+
+ }
+
+ if (close(normal_coverage_fd) < 0) {
+
+ FATAL("Failed to close coverage output file");
+
+ }
+
+ if (close(normal_coverage_pipes[STDIN_FILENO]) != 0) {
+
+ FATAL("Failed to close parent read pipe");
+
+ }
+
+}
+
+void instrument_coverage_unstable_find_output(void) {
+
+ pid_t parent = getpid();
+ gchar *fds_name = g_strdup_printf("/proc/%d/fd/", getppid());
+
+ gchar *root = g_file_read_link("/proc/self/root", NULL);
+ if (root == NULL) { FATAL("Failed to read link"); }
+
+ GDir *dir = g_dir_open(fds_name, 0, NULL);
+
+ OKF("Coverage Unstable - fds: %s", fds_name);
+
+ for (const gchar *filename = g_dir_read_name(dir); filename != NULL;
+ filename = g_dir_read_name(dir)) {
+
+ gchar *fullname = g_build_path("/", fds_name, filename, NULL);
+
+ gchar *link = g_file_read_link(fullname, NULL);
+ if (link == NULL) { FATAL("Failed to read link: %s", fullname); }
+
+ gchar *basename = g_path_get_basename(link);
+ if (g_strcmp0(basename, "default") != 0) {
+
+ g_free(basename);
+ g_free(link);
+ g_free(fullname);
+ continue;
+
+ }
+
+ gchar *relative = NULL;
+ size_t root_len = strnlen(root, PATH_MAX);
+ if (g_str_has_suffix(link, root)) {
+
+ relative = g_build_path("/", &link[root_len], NULL);
+
+ } else {
+
+ relative = g_build_path("/", link, NULL);
+
+ }
+
+ gchar *cmdline = g_build_path("/", relative, "cmdline", NULL);
+ if (!g_file_test(cmdline, G_FILE_TEST_EXISTS)) {
+
+ g_free(cmdline);
+ g_free(basename);
+ g_free(relative);
+ g_free(link);
+ g_free(fullname);
+ continue;
+
+ }
+
+ unstable_coverage_fuzzer_stats =
+ g_build_path("/", relative, "fuzzer_stats", NULL);
+ g_free(cmdline);
+ g_free(basename);
+ g_free(relative);
+ g_free(link);
+ g_free(fullname);
+ break;
+
+ }
+
+ g_dir_close(dir);
+ g_free(fds_name);
+
+ if (unstable_coverage_fuzzer_stats == NULL) {
+
+ FATAL("Failed to find fuzzer stats");
+
+ }
+
+ OKF("Fuzzer stats: %s", unstable_coverage_fuzzer_stats);
+
+}
+
+void instrument_coverage_unstable_init(void) {
+
+ if (instrument_coverage_unstable_filename == NULL) { return; }
+
+ char *path = g_canonicalize_filename(instrument_coverage_unstable_filename,
+ g_get_current_dir());
+
+ OKF("Coverage - unstable path [%s]", instrument_coverage_unstable_filename);
+
+ unstable_coverage_fd = open(path, O_RDWR | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+
+ if (unstable_coverage_fd < 0) {
+
+ FATAL("Failed to open unstable coverage file '%s'", path);
+
+ }
+
+ g_free(path);
+
+ instrument_coverage_unstable_find_output();
+
+ if (pipe(unstable_coverage_pipes) != 0) {
+
+ FATAL("Failed to create unstable pipes");
}
@@ -338,12 +820,19 @@ void instrument_coverage_init(void) {
if (pid == 0) {
- instrument_coverage_run();
+ instrument_coverage_unstable_run();
+ kill(getpid(), SIGKILL);
_exit(0);
}
- if (close(coverage_pipes[STDIN_FILENO]) != 0) {
+ if (close(unstable_coverage_fd) < 0) {
+
+ FATAL("Failed to close unstable coverage output file");
+
+ }
+
+ if (close(unstable_coverage_pipes[STDIN_FILENO]) != 0) {
FATAL("Failed to close parent read pipe");
@@ -351,20 +840,31 @@ void instrument_coverage_init(void) {
}
+void instrument_coverage_init(void) {
+
+ instrument_coverage_normal_init();
+ instrument_coverage_unstable_init();
+
+}
+
void instrument_coverage_start(uint64_t address) {
- coverage_last_start = address;
+ if (instrument_coverage_filename == NULL) { return; }
+
+ normal_coverage_last_start = address;
}
void instrument_coverage_end(uint64_t address) {
- coverage_data_t data = {
+ if (instrument_coverage_filename == NULL) { return; }
+
+ normal_coverage_data_t data = {
- .start = coverage_last_start, .end = address, .module = NULL};
+ .start = normal_coverage_last_start, .end = address, .module = NULL};
- if (write(coverage_pipes[STDOUT_FILENO], &data, sizeof(coverage_data_t)) !=
- sizeof(coverage_data_t)) {
+ if (write(normal_coverage_pipes[STDOUT_FILENO], &data,
+ sizeof(normal_coverage_data_t)) != sizeof(normal_coverage_data_t)) {
FATAL("Coverage I/O error");
@@ -372,3 +872,26 @@ void instrument_coverage_end(uint64_t address) {
}
+void instrument_coverage_unstable(guint64 edge, guint64 previous_rip,
+ guint64 previous_end, guint64 current_rip,
+ guint64 current_end) {
+
+ if (instrument_coverage_unstable_filename == NULL) { return; }
+ unstable_coverage_data_t data = {
+
+ .edge = edge,
+ .from = previous_rip,
+ .from_end = previous_end,
+ .to = current_rip,
+ .to_end = current_end};
+
+ if (write(unstable_coverage_pipes[STDOUT_FILENO], &data,
+ sizeof(unstable_coverage_data_t)) !=
+ sizeof(unstable_coverage_data_t)) {
+
+ FATAL("Unstable coverage I/O error");
+
+ }
+
+}
+