[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH AFL] Fuzzing the hypervisor
Changes based on version 2.43b of AFL --- Makefile | 2 +- afl-fuzz.c | 233 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- hash_map.h | 82 ++++++++++++++++++++++ 3 files changed, 306 insertions(+), 11 deletions(-) create mode 100644 hash_map.h diff --git a/Makefile b/Makefile index 44d1ffa..3a75c8c 100644 --- a/Makefile +++ b/Makefile @@ -70,7 +70,7 @@ afl-as: afl-as.c afl-as.h $(COMM_HDR) | test_x86 ln -sf afl-as as afl-fuzz: afl-fuzz.c $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS) + $(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS) -lxenctrl afl-showmap: afl-showmap.c $(COMM_HDR) | test_x86 $(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS) diff --git a/afl-fuzz.c b/afl-fuzz.c index 562fd50..08fa346 100644 --- a/afl-fuzz.c +++ b/afl-fuzz.c @@ -56,6 +56,10 @@ #include <sys/ioctl.h> #include <sys/file.h> +#include <xenctrl.h> +#include <xen/public/trace_pc.h> +#include "hash_map.h" + #if defined(__APPLE__) || defined(__FreeBSD__) || defined (__OpenBSD__) # include <sys/sysctl.h> #endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */ @@ -80,6 +84,25 @@ really makes no sense to haul them around as function parameters. */ +/* number of buckets in the hash map */ +#define NUM_BUCKETS 1000 +/* number of bytes written to xtf */ +#define SIZE_MEM_WRITE_TO_TESTCASE 80 +/* path for the file containing the last test case */ +#define TEST_CASE_LOG_PATH "/var/log/testcase" +/* path for the file containing all test cases */ +#define OVERALL_LOG_PATH "/var/log/afl.log" +#define XENCONSOLE_PATH "/usr/local/lib/xen/bin/xenconsole" + +int pipefd_to_xtf[2]; +int pipefd_from_xtf[2]; +char* domain; +hash_map* map; + +long mem_write_to_testcase[SIZE_MEM_WRITE_TO_TESTCASE]; + +FILE* log_file; + EXP_ST u8 *in_dir, /* Input directory with test cases */ *out_file, /* File to fuzz, if any */ *out_dir, /* Working & output directory */ @@ -2253,6 +2276,107 @@ EXP_ST void init_forkserver(char** argv) { } +/** Process program counters into format expected by AFL and + insert into trace_bits. + + cur_location = <COMPILE_TIME_RANDOM>; + shared_mem[cur_location ^ prev_location]++; + prev_location = cur_location >> 1; +*/ +void process_program_counters(uint64_t* pc_buffer, long pc_num) { + + u32 cur_location = 0, prev_location = 0; + hash_bucket* bucket; + + for(int i = 0; i < pc_num; ++i) { + bucket = _hash_map_lookup(map, pc_buffer[i]); + + if( !bucket ) { + cur_location = UR(MAP_SIZE); + if(!_hash_map_insert(map, pc_buffer[i], cur_location)) + FATAL("process_program_counters: Could not insert into hash map\n"); + } else { + cur_location = bucket->val; + } + + trace_bits[(cur_location ^ prev_location) % MAP_SIZE]++; + prev_location = cur_location >> 1; + } + +} + +/* Send test case to XTF-server. */ + +static u8 send_test_to_xtf(char** argv, u32 timeout) { + + size_t buf_size = 100; + char buffer[buf_size]; + + int pc_buffer_size = 100000; + uint64_t pc_buffer[pc_buffer_size]; + long ret; + + /* log the test case that is about to be send */ + if( fprintf(log_file, "get_cur_time %ld %li %li %ld %ld %ld\n", + (long) get_cur_time(), + mem_write_to_testcase[0] % 41, + mem_write_to_testcase[1], + mem_write_to_testcase[2], + mem_write_to_testcase[3], + mem_write_to_testcase[4]) < 0 ) + FATAL("send_test_to_xtf: Couldn't write to file\n"); + + fflush(log_file); + memset(trace_bits, 0, MAP_SIZE); + + xc_interface *xch = xc_interface_open(NULL, NULL, 0); + if( xch == NULL ) { + fclose(log_file); + FATAL("send_test_to_xtf: Couldn't open xen interface\n"); + } + + if( xc_trace_pc(xch, atoi(domain), XEN_TRACE_PC_START, + pc_buffer_size, pc_buffer) < 0 ) { + fclose(log_file); + xc_interface_close(xch); + FATAL("send_test_to_xtf: Start edge_trace failed\n"); + } + + /* send tet case to XTF */ + if( write(pipefd_to_xtf[1], (char*) mem_write_to_testcase, + SIZE_MEM_WRITE_TO_TESTCASE) <= 0 ) { + fclose(log_file); + xc_interface_close(xch); + FATAL("send_test_to_xtf: Couldn't write to XTF\n"); + } + + /* XTF will message us when it's hypercall returned */ + if( read(pipefd_from_xtf[0], buffer, buf_size) < 0 ) { + fclose(log_file); + xc_interface_close(xch); + FATAL("send_test_to_xtf: Couldn't read from XTF\n"); + } + + ret = xc_trace_pc(xch, atoi(domain), 1, pc_buffer_size, pc_buffer); + xc_interface_close(xch); + + if( ret < 0 ) { + fclose(log_file); + FATAL("send_test_to_xtf: Stop edge_trace failed\n"); + } + + process_program_counters(pc_buffer, ret); + +#ifdef __x86_64__ + classify_counts((u64*)trace_bits); +#else + classify_counts((u32*)trace_bits); +#endif /* ^__x86_64__ */ + + return FAULT_NONE; +} + + /* Execute target application, monitoring for timeouts. Return status information. The called program will update trace_bits[]. */ @@ -2455,13 +2579,21 @@ static u8 run_target(char** argv, u32 timeout) { } - /* Write modified data to file for testing. If out_file is set, the old file is unlinked and a new one is created. Otherwise, out_fd is rewound and truncated. */ static void write_to_testcase(void* mem, u32 len) { + memset((char*) mem_write_to_testcase, 0, SIZE_MEM_WRITE_TO_TESTCASE); + memcpy((char*) mem_write_to_testcase, mem, (len < SIZE_MEM_WRITE_TO_TESTCASE)?len:SIZE_MEM_WRITE_TO_TESTCASE); + + remove(TEST_CASE_LOG_PATH); + s32 my_file = open(TEST_CASE_LOG_PATH, O_WRONLY | O_CREAT | O_EXCL , 0600); + ck_write(my_file, mem, SIZE_MEM_WRITE_TO_TESTCASE, TEST_CASE_LOG_PATH); + fsync(my_file); + close(my_file); + s32 fd = out_fd; if (out_file) { @@ -2490,6 +2622,15 @@ static void write_to_testcase(void* mem, u32 len) { static void write_with_gap(void* mem, u32 len, u32 skip_at, u32 skip_len) { + memset((char*) mem_write_to_testcase, 0, SIZE_MEM_WRITE_TO_TESTCASE); + memcpy((char*) mem_write_to_testcase, mem, (len < SIZE_MEM_WRITE_TO_TESTCASE)?len:SIZE_MEM_WRITE_TO_TESTCASE); + + remove(TEST_CASE_LOG_PATH); + s32 my_file = open(TEST_CASE_LOG_PATH, O_WRONLY | O_CREAT | O_EXCL , 0600); + ck_write(my_file, mem, SIZE_MEM_WRITE_TO_TESTCASE, TEST_CASE_LOG_PATH); + fsync(my_file); + close(my_file); + s32 fd = out_fd; u32 tail_len = len - skip_at - skip_len; @@ -2568,7 +2709,7 @@ static u8 calibrate_case(char** argv, struct queue_entry* q, u8* use_mem, write_to_testcase(use_mem, q->len); - fault = run_target(argv, use_tmout); + fault = send_test_to_xtf(argv, use_tmout); /* stop_soon is set by the handler for Ctrl+C. When it's pressed, we want to bail out quickly. */ @@ -3198,7 +3339,7 @@ static u8 save_if_interesting(char** argv, void* mem, u32 len, u8 fault) { u8 new_fault; write_to_testcase(mem, len); - new_fault = run_target(argv, hang_tmout); + new_fault = send_test_to_xtf(argv, hang_tmout); if (stop_soon || new_fault != FAULT_TMOUT) return keeping; @@ -4479,7 +4620,7 @@ static u8 trim_case(char** argv, struct queue_entry* q, u8* in_buf) { write_with_gap(in_buf, q->len, remove_pos, trim_avail); - fault = run_target(argv, exec_tmout); + fault = send_test_to_xtf(argv, exec_tmout); trim_execs++; if (stop_soon || fault == FAULT_ERROR) goto abort_trimming; @@ -4572,7 +4713,7 @@ EXP_ST u8 common_fuzz_stuff(char** argv, u8* out_buf, u32 len) { write_to_testcase(out_buf, len); - fault = run_target(argv, exec_tmout); + fault = send_test_to_xtf(argv, exec_tmout); if (stop_soon) return 1; @@ -6701,7 +6842,7 @@ static void sync_fuzzers(char** argv) { write_to_testcase(mem, st.st_size); - fault = run_target(argv, exec_tmout); + fault = send_test_to_xtf(argv, exec_tmout); if (stop_soon) return; @@ -7665,6 +7806,73 @@ static void save_cmdline(u32 argc, char** argv) { } +/** + * @param domid_s Point to domid of XTF + * + * This function does initial setup needed for the fuzzing. It also + * sets up pipes such that stdout and stdin can be used to communicate + * with the XTF-server. + * + * TODO make this two separate functions + */ +static void setup_pipe_and_fork(char *domid_s) { + map = _hash_map_create(NUM_BUCKETS); + + if(!map) { + FATAL("setup_pipe_and_fork: Hash map could not be created\n"); + } + + log_file = fopen(OVERALL_LOG_PATH, "w"); + + if(log_file < 0) + goto FAIL; + + pid_t childpid; + int ret; + + if( (ret = pipe(pipefd_to_xtf)) < 0) + goto FAIL; + + if( (ret = pipe(pipefd_from_xtf)) < 0) + goto FAIL; + + if((childpid = fork()) == -1) + FATAL("setup_pipe_and_fork: fork failed"); + + if (childpid == 0) { /* child */ + + /* close unnecessary pipe ends */ + close(pipefd_to_xtf[1]); + close(pipefd_from_xtf[0]); + + /* stdin */ + close(0); + if( (ret = dup(pipefd_to_xtf[0])) < 0 ) + goto FAIL; + + /* stdout */ + close(1); + if( (ret = dup(pipefd_from_xtf[1])) < 0 ) + goto FAIL; + + if( execl(XENCONSOLE_PATH, XENCONSOLE_PATH, domid_s, "--num", "0", + "--type", "pv", "--interactive", (void *)NULL) < 0 ) + FATAL("setup_pipe_and_fork: execl"); + + } else { /* parent */ + + /* close unnecessary pipe ends */ + close(pipefd_to_xtf[0]); + close(pipefd_from_xtf[1]); + + } + + return; + + FAIL: + FATAL("setup_pipe_and_fork: Failed to setup pipes\n"); +} + #ifndef AFL_LIB @@ -7690,7 +7898,7 @@ int main(int argc, char** argv) { gettimeofday(&tv, &tz); srandom(tv.tv_sec ^ tv.tv_usec ^ getpid()); - while ((opt = getopt(argc, argv, "+i:o:f:m:t:T:dnCB:S:M:x:Q")) > 0) + while ((opt = getopt(argc, argv, "+i:o:f:m:t:T:dnCB:S:M:x:Qr:")) > 0) switch (opt) { @@ -7858,6 +8066,12 @@ int main(int argc, char** argv) { break; + case 'r': /* domain id for XTF server */ + + domain = optarg; + printf("domain set: %s\n", domain); + break; + default: usage(argv[0]); @@ -7935,8 +8149,6 @@ int main(int argc, char** argv) { if (!out_file) setup_stdio_file(); - check_binary(argv[optind]); - start_time = get_cur_time(); if (qemu_mode) @@ -7944,6 +8156,8 @@ int main(int argc, char** argv) { else use_argv = argv + optind; + setup_pipe_and_fork(domain); + perform_dry_run(use_argv); cull_queue(); @@ -7966,7 +8180,6 @@ int main(int argc, char** argv) { } while (1) { - u8 skipped_fuzz; cull_queue(); diff --git a/hash_map.h b/hash_map.h new file mode 100644 index 0000000..e5e6602 --- /dev/null +++ b/hash_map.h @@ -0,0 +1,82 @@ +/* @file hash_map.h + * + */ + +typedef struct hash_bucket { + struct hash_bucket* next; + uint64_t key; + uint64_t val; +} hash_bucket; + +typedef struct hash_map { + hash_bucket** buckets; + int num_buckets; +} hash_map; + +uint64_t _hash_function(hash_map* map, uint64_t key) { + return (key % map->num_buckets); +} + +hash_map* _hash_map_create(int num_buckets) { + hash_map* map = (hash_map*) malloc(sizeof(hash_map)); + + if( map ) { + map->num_buckets = num_buckets; + map->buckets = (hash_bucket**) malloc(sizeof(hash_bucket*) * num_buckets); + + if( !map->buckets ) { + free(map); + return NULL; + } + + for(int i = 0; i < num_buckets; ++i) + map->buckets[i] = NULL; + } + + return map; +} + +void _hash_map_destroy(hash_map* map) { + //not implemented +} + +hash_bucket* _hash_map_lookup(hash_map* map, uint64_t key) { + uint64_t hash = _hash_function(map, key); + + if(map->buckets[hash] == NULL) { + return NULL; + } else { + hash_bucket* cur = map->buckets[hash]; + + while(cur->key != key && cur->next) + cur = cur->next; + + return cur; + } +} + +bool _hash_map_insert(hash_map* map, uint64_t key, uint64_t val) { + uint64_t hash = _hash_function(map, key); + + hash_bucket* bucket = (hash_bucket*) malloc(sizeof(hash_bucket)); + + if(!bucket) + return false; + + bucket->next = NULL; + bucket->key = key; + bucket->val = val; + + if(map->buckets[hash] == NULL) { + map->buckets[hash] = bucket; + } else { + hash_bucket* cur = map->buckets[hash]; + while(cur->next) { + cur = cur->next; + } + + cur->next = bucket; + } + + return true; +} -- 2.11.0 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |