void pre_calloc(void *wrapctx, OUT void **user_data) { void *drc; drc = drwrap_get_drcontext(wrapctx); dr_mutex_lock(lock); if (!module_is_wrapped(drc)) { dr_mutex_unlock(lock); return; } *user_data = add_block((size_t)drwrap_get_arg(wrapctx, 1) * (size_t)drwrap_get_arg(wrapctx, 0), get_prev_instr_pc(drwrap_get_retaddr(wrapctx), drc), drc); dr_mutex_unlock(lock); }
void post_realloc(void *wrapctx, void *user_data) { malloc_t *block; void *ret = drwrap_get_retval(wrapctx); void *drc = drwrap_get_drcontext(wrapctx);; realloc_tmp_t *data = user_data; // if user_data is not set realloc was called to do a free // or the call to realloc is an init call or the block // was alloc by a non wrap module if (data) { dr_mutex_lock(lock); if (data->block) { block = data->block; set_addr_malloc(block, ret, block->flag, 1); // we dont set the alloc arg in get_caller_data // because the post wrap happen after the return get_caller_data(&(block->alloc_func_pc), &(block->alloc_func_sym), &(block->alloc_module_name), drc, 0); block->alloc_pc = get_prev_instr_pc(drwrap_get_retaddr(wrapctx), drc); } // if realloc is use like a malloc set, we the size here // because malloc wrapper receive a null size else if ((block = search_on_tree(active_blocks, ret))) { block->size = data->size; block->end = block->start + block->size; } dr_global_free(user_data, sizeof(realloc_tmp_t)); dr_mutex_unlock(lock); } }
void pre_malloc(void *wrapctx, OUT void **user_data) { void *drc; drc = drwrap_get_drcontext(wrapctx); dr_mutex_lock(lock); /* // the first call on 64 bit and the second in 32bit */ /* // are init call, so we have to do nothing */ /* #ifdef BUILD_64 */ /* if (!malloc_init++ && !realloc_init) */ /* { */ /* dr_mutex_unlock(lock); */ /* return; */ /* } */ /* #else */ /* if (malloc_init++ == 1 && realloc_init != 1) */ /* { */ /* dr_mutex_unlock(lock); */ /* return; */ /* } */ /* #endif */ if (!module_is_wrapped(drc)) { dr_mutex_unlock(lock); return; } *user_data = add_block((size_t)drwrap_get_arg(wrapctx, 0), get_prev_instr_pc(drwrap_get_retaddr(wrapctx), drc), drc); dr_mutex_unlock(lock); }
static void pre_fuzz_handler(void *wrapcxt, INOUT void **user_data) { void *dcontext = drwrap_get_drcontext(wrapcxt); app_pc target_to_fuzz = drwrap_get_func(wrapcxt); fuzz_target_t *target = hashtable_lookup(&fuzz_target_htable, target_to_fuzz); fuzz_pass_context_t *fp = (fuzz_pass_context_t *) drmgr_get_tls_field(dcontext, tls_idx_fuzzer); bool is_target_entry = false; pass_target_t *live = NULL; dr_mcontext_t *mc; uint i; ASSERT(target != NULL, "pre_fuzz must be associated with a fuzz target"); DRFUZZ_LOG(3, "pre_fuzz() for target "PFX" with %d args\n", target_to_fuzz, target->arg_count); /* XXX i#1734: this heuristic may be incorrect when a handled fault occurs during * the very last iteration of the last fuzz pass on any thread. */ clear_thread_state(fp); /* Stop the target iterator that was captured at the last critical fault, because * the fact that we are in pre-fuzz implies the fault was handled and doesn't matter. */ if (fp->thread_state->targets != NULL) drfuzz_target_iterator_stop(fp->thread_state->targets); /* XXX: assumes the fuzz target is never called recursively */ if (fp->live_targets != NULL && fp->live_targets->target->func_pc == target_to_fuzz) { live = fp->live_targets; /* this is a repetition of the last live target */ } else { is_target_entry = true; /* this is a new invocation of a target */ live = activate_cached_target(fp, target_to_fuzz); /* check the cache */ if (live == NULL) live = create_pass_target(dcontext, wrapcxt); live->next = fp->live_targets; /* push to live stack */ fp->live_targets = live; } /* required by dr_redirect_execution() (avoids having to merge the mcontext) */ mc = drwrap_get_mcontext_ex(wrapcxt, DR_MC_ALL); /* XXX: can we relax this? */ if (is_target_entry) { live->xsp = mc->xsp; #ifdef X86 live->unclobber.retaddr_loc = (reg_t *) mc->xsp; /* see retaddr_unclobber_t */ #endif live->unclobber.retaddr = (reg_t) drwrap_get_retaddr(wrapcxt); DRFUZZ_LOG(4, "fuzz target "PFX": saving stack pointer "PFX"\n", target_to_fuzz, mc->xsp); for (i = 0; i < target->arg_count; i++) { /* store the original arg values */ live->original_args[i] = (reg_t) drwrap_get_arg(wrapcxt, i); /* copy original args to current args for the first iteration of the fuzz */ live->current_args[i] = live->original_args[i]; DRFUZZ_LOG(4, "fuzz target "PFX": saving original arg #%d: "PFX"\n", target_to_fuzz, i, live->original_args[i]); } } /* restore the original arg values before calling the client */ for (i = 0; i < target->arg_count; i++) { DRFUZZ_LOG(4, "fuzz target "PFX": restoring original arg #%d: "PFX"\n", target_to_fuzz, i, live->original_args[i]); drwrap_set_arg(wrapcxt, i, (void *) live->original_args[i]); } #ifdef ARM mc->lr = live->unclobber.retaddr; /* restore retaddr to link register */ #else /* X86 */ *live->unclobber.retaddr_loc = live->unclobber.retaddr; /* restore retaddr to stack */ #endif target->pre_fuzz_cb(fp, (generic_func_t) target_to_fuzz, mc); drwrap_set_mcontext(wrapcxt); for (i = 0; i < target->arg_count; i++) live->current_args[i] = (reg_t) drwrap_get_arg(wrapcxt, i); *user_data = fp; }
void pre_realloc(void *wrapctx, OUT void **user_data) { malloc_t *block; malloc_t *new_block; realloc_tmp_t *tmp = NULL; void *start = drwrap_get_arg(wrapctx, 0); size_t size = (size_t)drwrap_get_arg(wrapctx, 1); void *drc = drwrap_get_drcontext(wrapctx); dr_mutex_lock(lock); /* // the first call on 64 bit and the second in 32bit */ /* // are init call, so we have to do nothing */ /* #ifdef BUILD_64 */ /* if (!realloc_init) */ /* { */ /* realloc_init++; */ /* dr_mutex_unlock(lock); */ /* return; */ /* } */ /* #else */ /* if (realloc_init++ == 1) */ /* { */ /* dr_mutex_unlock(lock); */ /* return; */ /* } */ /* #endif */ // if size == 0, realloc call free if (!size) { // this can happen if a block is alloc by a non wrap module and realloc // on a wrapped one if (!(block = search_on_tree(active_blocks, start))) { dr_mutex_unlock(lock); return; } block->free_pc = get_prev_instr_pc(drwrap_get_retaddr(wrapctx), drc); get_caller_data(&(block->free_func_pc), &(block->free_func_sym), &(block->free_module_name), drc, 1); dr_mutex_unlock(lock); return; } if (!(tmp = dr_global_alloc(sizeof(realloc_tmp_t)))) { dr_printf("dr_malloc fail\n"); dr_mutex_unlock(lock); return; } // if realloc is use like malloc save the size to set it on the post wrapping tmp->size = size; *user_data = tmp; // if start == 0, realloc call malloc if (!start) { // if a block is alloc by a wrapped function and realloc by // an unwrapped one we have to take the realloc // so when realloc is called to do a malloc is the only case // when we have to check if the module is wrapped if(!module_is_wrapped(drc)) { *user_data = NULL; dr_global_free(tmp, sizeof(*tmp)); dr_mutex_unlock(lock); return; } tmp->block = NULL; dr_mutex_unlock(lock); return; } // this can happen if the block is alloc by a non wrapped module if (!(block = search_on_tree(active_blocks, start))) { *user_data = NULL; dr_global_free(tmp, sizeof(*tmp)); dr_mutex_unlock(lock); return; } else { del_from_tree(&active_blocks, start, NULL, false); if ((new_block = dr_custom_alloc(NULL, 0, sizeof(*new_block), DR_MEMPROT_WRITE | DR_MEMPROT_READ, NULL))) { block->flag |= FREE_BY_REALLOC; block->free_pc = get_prev_instr_pc(drwrap_get_retaddr(wrapctx), drc); get_caller_data(&(block->free_func_pc), &(block->free_func_sym), &(block->free_module_name), drc, 1); block->next = old_blocks; old_blocks = block; old_blocks_count++; if (!args->console && old_blocks_count == MAX_OLD_BLOCKS) { flush_old_block(); old_blocks_count = 0; } ds_memset(new_block, 0, sizeof(*new_block)); new_block->flag |= ALLOC_BY_REALLOC; block = new_block; } else dr_printf("fail alloc\n"); block->size = size; } tmp->block = block; dr_mutex_unlock(lock); }