From 74c290d851e848825fa60669a606a58eadab8e74 Mon Sep 17 00:00:00 2001 From: Sergej Schumilo Date: Sun, 23 Jul 2023 14:52:13 +0200 Subject: [PATCH 1/4] add yaml serializer for snapshot meta data --- nyx/fast_vm_reload_sync.c | 2 + nyx/state/snapshot_state.c | 83 ++++++++++++++++++++++++++++++++++++++ nyx/state/snapshot_state.h | 2 + 3 files changed, 87 insertions(+) diff --git a/nyx/fast_vm_reload_sync.c b/nyx/fast_vm_reload_sync.c index 165c417132..8db2dc0ace 100644 --- a/nyx/fast_vm_reload_sync.c +++ b/nyx/fast_vm_reload_sync.c @@ -131,6 +131,8 @@ static inline void create_root_snapshot(void) fast_reload_create_in_memory(get_fast_reload_snapshot()); fast_reload_serialize_to_file(get_fast_reload_snapshot(), GET_GLOBAL_STATE()->fast_reload_path, false); + + serialize_root_snapshot_meta_data(GET_GLOBAL_STATE()->fast_reload_path); } } else { nyx_debug("===> GET_GLOBAL_STATE()->fast_reload_enabled: FALSE\n"); diff --git a/nyx/state/snapshot_state.c b/nyx/state/snapshot_state.c index b7b62d2933..a10ec84227 100644 --- a/nyx/state/snapshot_state.c +++ b/nyx/state/snapshot_state.c @@ -152,3 +152,86 @@ void deserialize_state(const char *filename_prefix) free(tmp); } + +static bool yaml_write_bool(FILE *fp, const char *key, bool value) +{ + return fprintf(fp, " %s: %s\n", key, value ? "true" : "false") != -1; +} + +static bool yaml_write_uint64(FILE *fp, const char *key, uint64_t value) +{ + return fprintf(fp, " %s: 0x%" PRIx64 "\n", key, value) != -1; +} + +static bool yaml_write_uint64_range(FILE *fp, const char *key, uint64_t value_a, uint64_t value_b) +{ + return fprintf(fp, " %s: [0x%" PRIx64 ", 0x%" PRIx64 "]\n", key, value_a, value_b) != -1; +} + +/* Helper function to serialize the meta data of a snapshot to yaml. + * This function is only called in case a root snapshot is created. + * The data written to the yaml file is not used later on, but can be used + * by the frontend to get specific information about the snapshot. + */ +void serialize_root_snapshot_meta_data(const char *snapshot_dir){ + nyx_trace(); + + char *tmp; + + assert(asprintf(&tmp, "%s/state.yaml", snapshot_dir) != -1); + + FILE *fp = fopen(tmp, "wb"); + if (fp == NULL) { + nyx_error("[%s] Could not open file %s.\n", __func__, tmp); + assert(false); + } + + qemu_nyx_state_t *nyx_global_state = GET_GLOBAL_STATE(); + + assert(fprintf(fp, "---\n") != -1); + + assert(fprintf(fp, "process_trace:\n") != 1); + for (uint8_t i = 0; i < 4; i++) { + char* key = NULL; + assert(asprintf(&key, "pt_ip_filter_configured_%d", i) != -1); + assert(yaml_write_bool(fp, key, nyx_global_state->pt_ip_filter_configured[i])); + free(key); + } + + for (uint8_t i = 0; i < 4; i++) { + char* key = NULL; + assert(asprintf(&key, "pt_ip_filter_%d", i) != -1); + assert(yaml_write_uint64_range(fp, key, nyx_global_state->pt_ip_filter_a[i], nyx_global_state->pt_ip_filter_b[i])); + free(key); + } + + assert(yaml_write_uint64(fp, "parent_cr3", nyx_global_state->parent_cr3)); + assert(yaml_write_uint64(fp, "disassembler_word_width", nyx_global_state->disassembler_word_width)); + //assert(yaml_write_uint64(fp, "fast_reload_pre_image", nyx_global_state->fast_reload_pre_image)); + assert(yaml_write_uint64(fp, "mem_mode", nyx_global_state->mem_mode)); /* improve? */ + assert(yaml_write_bool(fp, "pt_trace_mode", nyx_global_state->pt_trace_mode)); + assert(fprintf(fp, "\n") != -1); + + + assert(fprintf(fp, "input_buffer:\n") != -1); + assert(yaml_write_uint64(fp, "input_buffer_vaddr", nyx_global_state->payload_buffer)); + assert(yaml_write_bool(fp, "protect_input_buffer", nyx_global_state->protect_payload_buffer)); + assert(yaml_write_uint64(fp, "input_buffer_size", nyx_global_state->input_buffer_size)); + assert(fprintf(fp, "\n") != -1); + + + assert(fprintf(fp, "capabilites:\n") != -1); + assert(yaml_write_bool(fp, "cap_timeout_detection", nyx_global_state->cap_timeout_detection)); + assert(yaml_write_bool(fp, "cap_only_reload_mode", nyx_global_state->cap_only_reload_mode)); + assert(yaml_write_bool(fp, "cap_compile_time_tracing", nyx_global_state->cap_compile_time_tracing)); + assert(yaml_write_bool(fp, "cap_ijon_tracing", nyx_global_state->cap_ijon_tracing)); + assert(yaml_write_bool(fp, "cap_cr3", nyx_global_state->cap_cr3)); + assert(yaml_write_uint64(fp, "cap_compile_time_tracing_buffer_vaddr", nyx_global_state->cap_compile_time_tracing_buffer_vaddr)); + assert(yaml_write_uint64(fp, "cap_ijon_tracing_buffer_vaddr", nyx_global_state->cap_ijon_tracing_buffer_vaddr)); + assert(yaml_write_uint64(fp, "cap_coverage_bitmap_size", nyx_global_state->cap_coverage_bitmap_size)); + assert(fprintf(fp, "\n") != -1); + + assert(fprintf(fp, "...\n") != -1); + fclose(fp); + free(tmp); +} \ No newline at end of file diff --git a/nyx/state/snapshot_state.h b/nyx/state/snapshot_state.h index fa9491795f..c7920709d5 100644 --- a/nyx/state/snapshot_state.h +++ b/nyx/state/snapshot_state.h @@ -44,3 +44,5 @@ typedef struct serialized_state_root_snapshot_s { void serialize_state(const char *filename_prefix, bool is_pre_snapshot); void deserialize_state(const char *filename_prefix); + +void serialize_root_snapshot_meta_data(const char *snapshot_dir); \ No newline at end of file From b20b0942fc34f9f97996fdbefe5b44b45fb26883 Mon Sep 17 00:00:00 2001 From: Sergej Schumilo Date: Wed, 2 Aug 2023 11:18:50 +0200 Subject: [PATCH 2/4] extend yaml writer and add version and mem_mode --- nyx/state/snapshot_state.c | 60 +++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/nyx/state/snapshot_state.c b/nyx/state/snapshot_state.c index a10ec84227..ba68cd72a9 100644 --- a/nyx/state/snapshot_state.c +++ b/nyx/state/snapshot_state.c @@ -158,16 +158,45 @@ static bool yaml_write_bool(FILE *fp, const char *key, bool value) return fprintf(fp, " %s: %s\n", key, value ? "true" : "false") != -1; } -static bool yaml_write_uint64(FILE *fp, const char *key, uint64_t value) +static bool yaml_write_uint64_x(FILE *fp, const char *key, uint64_t value) { return fprintf(fp, " %s: 0x%" PRIx64 "\n", key, value) != -1; } -static bool yaml_write_uint64_range(FILE *fp, const char *key, uint64_t value_a, uint64_t value_b) +static bool yaml_write_uint64_d(FILE *fp, const char *key, uint64_t value) +{ + return fprintf(fp, " %s: %" PRId64 "\n", key, value) != -1; +} + +static bool yaml_write_uint64_x_range(FILE *fp, const char *key, uint64_t value_a, uint64_t value_b) { return fprintf(fp, " %s: [0x%" PRIx64 ", 0x%" PRIx64 "]\n", key, value_a, value_b) != -1; } +static void yaml_write_mem_mode(FILE *fp, const char *key, mem_mode_t value) +{ + switch (value) { + case mm_unkown: + assert(fprintf(fp, " %s: \"mm_unkown\"\n", key) != 1); + break; + case mm_32_protected: /* 32 Bit / No MMU */ + assert(fprintf(fp, " %s: \"mm_32_protected\"\n", key) != 1); + break; + case mm_32_paging: /* 32 Bit / PAE Paging */ + assert(fprintf(fp, " %s: \"mm_32_paging\"\n", key) != 1); + break; + case mm_32_pae: /* 32 Bit / PAE Paging */ + assert(fprintf(fp, " %s: \"mm_32_pae\"\n", key) != 1); + break; + case mm_64_l4_paging: /* 64 Bit / L4 Paging */ + assert(fprintf(fp, " %s: \"mm_64_l4_paging\"\n", key) != 1); + break; + case mm_64_l5_paging: /* 64 Bit / L5 Paging */ + assert(fprintf(fp, " %s: \"mm_64_l5_paging\"\n", key) != 1); + break; + } +} + /* Helper function to serialize the meta data of a snapshot to yaml. * This function is only called in case a root snapshot is created. * The data written to the yaml file is not used later on, but can be used @@ -190,7 +219,11 @@ void serialize_root_snapshot_meta_data(const char *snapshot_dir){ assert(fprintf(fp, "---\n") != -1); - assert(fprintf(fp, "process_trace:\n") != 1); + assert(fprintf(fp, "qemu_nyx:\n") != 1); + assert(yaml_write_uint64_x(fp, "nyx_serialized_state_version", NYX_SERIALIZED_STATE_VERSION)); + assert(fprintf(fp, "\n") != -1); + + assert(fprintf(fp, "processor_trace:\n") != 1); for (uint8_t i = 0; i < 4; i++) { char* key = NULL; assert(asprintf(&key, "pt_ip_filter_configured_%d", i) != -1); @@ -201,22 +234,23 @@ void serialize_root_snapshot_meta_data(const char *snapshot_dir){ for (uint8_t i = 0; i < 4; i++) { char* key = NULL; assert(asprintf(&key, "pt_ip_filter_%d", i) != -1); - assert(yaml_write_uint64_range(fp, key, nyx_global_state->pt_ip_filter_a[i], nyx_global_state->pt_ip_filter_b[i])); + assert(yaml_write_uint64_x_range(fp, key, nyx_global_state->pt_ip_filter_a[i], nyx_global_state->pt_ip_filter_b[i])); free(key); } - assert(yaml_write_uint64(fp, "parent_cr3", nyx_global_state->parent_cr3)); - assert(yaml_write_uint64(fp, "disassembler_word_width", nyx_global_state->disassembler_word_width)); - //assert(yaml_write_uint64(fp, "fast_reload_pre_image", nyx_global_state->fast_reload_pre_image)); - assert(yaml_write_uint64(fp, "mem_mode", nyx_global_state->mem_mode)); /* improve? */ + assert(yaml_write_uint64_x(fp, "parent_cr3", nyx_global_state->parent_cr3)); + /* TODO: remove disassembler_word_width (it is actually not used or set anymore) */ + //assert(yaml_write_uint64_d(fp, "disassembler_word_width", nyx_global_state->disassembler_word_width)); + //assert(yaml_write_uint64_x(fp, "fast_reload_pre_image", nyx_global_state->fast_reload_pre_image)); + yaml_write_mem_mode(fp, "mem_mode", nyx_global_state->mem_mode); assert(yaml_write_bool(fp, "pt_trace_mode", nyx_global_state->pt_trace_mode)); assert(fprintf(fp, "\n") != -1); assert(fprintf(fp, "input_buffer:\n") != -1); - assert(yaml_write_uint64(fp, "input_buffer_vaddr", nyx_global_state->payload_buffer)); + assert(yaml_write_uint64_x(fp, "input_buffer_vaddr", nyx_global_state->payload_buffer)); assert(yaml_write_bool(fp, "protect_input_buffer", nyx_global_state->protect_payload_buffer)); - assert(yaml_write_uint64(fp, "input_buffer_size", nyx_global_state->input_buffer_size)); + assert(yaml_write_uint64_x(fp, "input_buffer_size", nyx_global_state->input_buffer_size)); assert(fprintf(fp, "\n") != -1); @@ -226,9 +260,9 @@ void serialize_root_snapshot_meta_data(const char *snapshot_dir){ assert(yaml_write_bool(fp, "cap_compile_time_tracing", nyx_global_state->cap_compile_time_tracing)); assert(yaml_write_bool(fp, "cap_ijon_tracing", nyx_global_state->cap_ijon_tracing)); assert(yaml_write_bool(fp, "cap_cr3", nyx_global_state->cap_cr3)); - assert(yaml_write_uint64(fp, "cap_compile_time_tracing_buffer_vaddr", nyx_global_state->cap_compile_time_tracing_buffer_vaddr)); - assert(yaml_write_uint64(fp, "cap_ijon_tracing_buffer_vaddr", nyx_global_state->cap_ijon_tracing_buffer_vaddr)); - assert(yaml_write_uint64(fp, "cap_coverage_bitmap_size", nyx_global_state->cap_coverage_bitmap_size)); + assert(yaml_write_uint64_x(fp, "cap_compile_time_tracing_buffer_vaddr", nyx_global_state->cap_compile_time_tracing_buffer_vaddr)); + assert(yaml_write_uint64_x(fp, "cap_ijon_tracing_buffer_vaddr", nyx_global_state->cap_ijon_tracing_buffer_vaddr)); + assert(yaml_write_uint64_x(fp, "cap_coverage_bitmap_size", nyx_global_state->cap_coverage_bitmap_size)); assert(fprintf(fp, "\n") != -1); assert(fprintf(fp, "...\n") != -1); From 564ece0384e6c0bfaa186a579071662fd32b32b4 Mon Sep 17 00:00:00 2001 From: Sergej Schumilo Date: Wed, 2 Aug 2023 11:19:08 +0200 Subject: [PATCH 3/4] fix typo in mem_mode enum --- nyx/types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nyx/types.h b/nyx/types.h index 6c331b182e..24457e2c6d 100644 --- a/nyx/types.h +++ b/nyx/types.h @@ -6,7 +6,7 @@ enum mem_mode { mm_32_paging, /* 32 Bit / L3 Paging */ mm_32_pae, /* 32 Bit / PAE Paging */ mm_64_l4_paging, /* 64 Bit / L4 Paging */ - mm_64_l5_paging, /* 32 Bit / L5 Paging */ + mm_64_l5_paging, /* 64 Bit / L5 Paging */ }; typedef uint8_t mem_mode_t; From 6a089f758040be3850d978d3f1607de92a54b797 Mon Sep 17 00:00:00 2001 From: Sergej Schumilo Date: Wed, 2 Aug 2023 11:24:25 +0200 Subject: [PATCH 4/4] export yaml state file even if snapshot serialization is disabled --- nyx/fast_vm_reload_sync.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/nyx/fast_vm_reload_sync.c b/nyx/fast_vm_reload_sync.c index 8db2dc0ace..7c83b1b727 100644 --- a/nyx/fast_vm_reload_sync.c +++ b/nyx/fast_vm_reload_sync.c @@ -19,6 +19,7 @@ #include "nyx/fast_vm_reload.h" #include "nyx/kvm_nested.h" #include "nyx/state/state.h" +#include "nyx/state/snapshot_state.h" extern int save_snapshot(const char *name, Error **errp); extern int load_snapshot(const char *name, Error **errp); @@ -138,6 +139,16 @@ static inline void create_root_snapshot(void) nyx_debug("===> GET_GLOBAL_STATE()->fast_reload_enabled: FALSE\n"); /* so we haven't set a path for our snapshot files - just store everything in memory */ fast_reload_create_in_memory(get_fast_reload_snapshot()); + + /* Even if we don't serialize the snapshot we still want to have the + * option to export the meta data of the root snapshot as yaml file. + * This might be useful for the fuzzing frontend in charge; thus it + * is also up to the frontend to set a path for the snapshot directory. + * If the path is not set, we just skip this step. + */ + if (GET_GLOBAL_STATE()->fast_reload_path != NULL) { + serialize_root_snapshot_meta_data(GET_GLOBAL_STATE()->fast_reload_path); + } } }