Пример #1
0
static void
wrap_pre_SSL_write(void *wrapcxt, OUT void **user_data)
{
    /* int SSL_write(SSL *ssl, const void *buf, int num);
     *
     * ssize_t gnutls_record_send(gnutls_session_t session,
     *                            const void * data, size_t sizeofdata);
     */

    void *ssl = (void *)drwrap_get_arg(wrapcxt, 0);
    unsigned char *buf = (unsigned char *)drwrap_get_arg(wrapcxt, 1);
    size_t sz = (size_t)drwrap_get_arg(wrapcxt, 2);

    /* By generating unique filenames (per SSL context), we are able to
     * simplify logging of SSL traffic (no file locking is required).
     */
    char filename[MAXIMUM_PATH] = { 0 };
    dr_snprintf(filename, BUFFER_SIZE_ELEMENTS(filename), "trace-%x.write", ssl);
    NULL_TERMINATE_BUFFER(filename);
    FILE *fp = fopen(filename, "ab+");
    /* Error handling of logging operations isn't critical - in fact, we don't
     * even know what to do in such error conditions, so we simply return!
     */
    if (!fp) {
        dr_fprintf(STDERR, "Couldn’t open the output file %s\n", filename);
        return;
    }

    /* We assume that SSL_write always succeeds and writes the whole buffer. */
    fwrite(buf, 1, sz, fp);
    fclose(fp);
}
Пример #2
0
static void wrap_realloc_pre(void *wrapctx, void **user_data)
{
    logging_paused++;
    void *ptr = drwrap_get_arg(wrapctx, 0);
    freed(ptr);
    *user_data = drwrap_get_arg(wrapctx, 1);
}
Пример #3
0
static void
wrap_pre_SSL_read(void *wrapcxt, OUT void **user_data)
{
    struct SSL_read_data *sd;

    /* int SSL_read(SSL *ssl, void *buf, int num);
     *
     * ssize_t gnutls_record_recv(gnutls_session_t session,
     *                            void * data, size_t sizeofdata);
     */

    sd = dr_global_alloc(sizeof(struct SSL_read_data));
    sd->read_buffer = (unsigned char *)drwrap_get_arg(wrapcxt, 1);
    sd->ssl = (void *)drwrap_get_arg(wrapcxt, 0);

    *user_data = (void *)sd;
}
Пример #4
0
static void
wrap_pre(void *wrapcxt, OUT void **user_data)
{
    bool ok;
    CHECK(wrapcxt != NULL && user_data != NULL, "invalid arg");
    if (drwrap_get_func(wrapcxt) == addr_skip_flags) {
        CHECK(drwrap_get_arg(wrapcxt, 0) == (void *) 1, "get_arg wrong");
        CHECK(drwrap_get_arg(wrapcxt, 1) == (void *) 2, "get_arg wrong");
    } else if (drwrap_get_func(wrapcxt) == addr_level0) {
        dr_fprintf(STDERR, "  <pre-level0>\n");
        CHECK(drwrap_get_arg(wrapcxt, 0) == (void *) 37, "get_arg wrong");
        ok = drwrap_set_arg(wrapcxt, 0, (void *) 42);
        CHECK(ok, "set_arg error");
        *user_data = (void *) 99;
    } else if (drwrap_get_func(wrapcxt) == addr_level1) {
        dr_fprintf(STDERR, "  <pre-level1>\n");
        ok = drwrap_set_arg(wrapcxt, 1, (void *) 1111);
        CHECK(ok, "set_arg error");
    } else if (drwrap_get_func(wrapcxt) == addr_tailcall) {
        dr_fprintf(STDERR, "  <pre-makes_tailcall>\n");
    } else if (drwrap_get_func(wrapcxt) == addr_level2) {
        dr_fprintf(STDERR, "  <pre-level2>\n");
    } else if (drwrap_get_func(wrapcxt) == addr_skipme) {
        dr_fprintf(STDERR, "  <pre-skipme>\n");
        drwrap_skip_call(wrapcxt, (void *) 7, 0);
    } else if (drwrap_get_func(wrapcxt) == addr_repeat) {
        dr_mcontext_t *mc = drwrap_get_mcontext(wrapcxt);
        dr_fprintf(STDERR, "  <pre-repeat#%d>\n", repeated ? 2 : 1);
        repeat_xsp = mc->xsp;
#ifdef ARM
        repeat_link = mc->lr;
#endif
        if (repeated) /* test changing the arg value on the second pass */
            drwrap_set_arg(wrapcxt, 0, (void *)2);
        CHECK(drwrap_redirect_execution(NULL) != DREXT_SUCCESS,
              "allowed redirect with NULL wrapcxt");
        CHECK(drwrap_redirect_execution(wrapcxt) != DREXT_SUCCESS,
              "allowed redirect in pre-wrap");
    } else if (drwrap_get_func(wrapcxt) == addr_preonly) {
        dr_fprintf(STDERR, "  <pre-preonly>\n");
    } else
        CHECK(false, "invalid wrap");
}
Пример #5
0
/*
 * We wrap the C library function memset, because I've noticed that at
 * least one optimised implementation of it diverges control flow
 * internally based on what appears to be the _alignment_ of the input
 * pointer - and that alignment check can vary depending on the
 * addresses of allocated blocks. So I can't guarantee no divergence
 * of control flow inside memset if malloc doesn't return the same
 * values, and instead I just have to trust that memset isn't reading
 * the contents of the block and basing control flow decisions on that.
 */
static void wrap_memset_pre(void *wrapctx, void **user_data)
{
    uint was_already_paused = logging_paused++;

    if (outfile == INVALID_FILE || was_already_paused)
        return;

    const void *addr = drwrap_get_arg(wrapctx, 0);
    size_t size = (size_t)drwrap_get_arg(wrapctx, 2);

    struct allocation *alloc = find_allocation(addr);
    if (!alloc) {
        dr_fprintf(outfile, "memset %"PRIuMAX" @ %"PRIxMAX"\n",
                   (uintmax_t)size, (uintmax_t)addr);
    } else {
        dr_fprintf(outfile, "memset %"PRIuMAX" @ allocations[%"PRIuPTR"]"
                   " + %"PRIxMAX"\n", (uintmax_t)size, alloc->index,
                   (uintmax_t)(addr - alloc->start));
    }
}
Пример #6
0
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);
}
Пример #7
0
/** Wrapper pre-callback. */
static void wrapperPre( void* ctx, void** data ) {
  dr_mutex_lock( outMutex );

  uint64 currentTimeMillis = dr_get_milliseconds();
  if( currentTimeMillis > nextTimestampMillis ) {
    dr_fprintf( outFile, "T 0x%.16llx\n", currentTimeMillis );
    nextTimestampMillis = currentTimeMillis + timestampIntervalMillis;
  }

  dr_fprintf( outFile, "X %p %p\n", (void*)drwrap_get_func( ctx ),
                                    drwrap_get_arg( ctx, 0 ) );
  dr_mutex_unlock( outMutex );
}
Пример #8
0
static void
wrap_pre(void *wrapcxt, OUT void **user_data)
{
    /* malloc(size) or HeapAlloc(heap, flags, size) */
    size_t sz = (size_t) drwrap_get_arg(wrapcxt, IF_WINDOWS_ELSE(2,0));
    /* find the maximum malloc request */
    if (sz > max_malloc) {
        dr_mutex_lock(max_lock);
        if (sz > max_malloc)
            max_malloc = sz;
        dr_mutex_unlock(max_lock);
    }
    *user_data = (void *) sz;
}
Пример #9
0
/*
 * Wrap the log_set_file() function in testsc.c, and respond to it by
 * opening or closing log files.
 */
static void wrap_logsetfile(void *wrapctx, void **user_data)
{
    if (outfile) {
        dr_close_file(outfile);
        outfile = INVALID_FILE;
    }

    const char *outfilename = drwrap_get_arg(wrapctx, 0);
    if (outfilename) {
        outfile = dr_open_file(outfilename, DR_FILE_WRITE_OVERWRITE);
        DR_ASSERT(outfile != INVALID_FILE);
    }

    /*
     * Reset the allocation list to empty, whenever we open or close a
     * log file.
     */
    while (alloc_ends->next != alloc_ends)
        free_allocation(alloc_ends->next);
    next_alloc_index = 0;
}
Пример #10
0
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);
}
Пример #11
0
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;
}
Пример #12
0
/*
 * The actual wrapper functions for malloc, realloc and free.
 */
static void wrap_malloc_pre(void *wrapctx, void **user_data)
{
    logging_paused++;
    *user_data = drwrap_get_arg(wrapctx, 0);
}
Пример #13
0
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);
}