Dr. Memory
drfuzz.h File Reference

Header for Dr. Fuzz: DynamoRIO Fuzz Testing Extension. More...

#include "drmemory_framework.h"
#include "drwrap.h"
#include "drfuzz_mutator.h"

Data Structures

struct  _drfuzz_target_frame_t
 
struct  _drfuzz_fault_t
 
struct  _drfuzz_fault_thread_state_t
 
struct  _drfuzz_crash_state_t
 

Typedefs

typedef struct _drfuzz_target_frame_t drfuzz_target_frame_t
 
typedef void * drfuzz_target_iterator_t
 
typedef struct _drfuzz_fault_t drfuzz_fault_t
 
typedef dr_siginfo_t drfuzz_fault_ex_t
 
typedef struct _drfuzz_fault_thread_state_t drfuzz_fault_thread_state_t
 
typedef struct _drfuzz_crash_state_t drfuzz_crash_state_t
 

Functions

DR_EXPORT drmf_status_t drfuzz_init (client_id_t client_id)
 
DR_EXPORT drmf_status_t drfuzz_exit (void)
 
DR_EXPORT drmf_status_t drfuzz_fuzz_target (generic_func_t func_pc, uint arg_count, uint flags, uint wrap_flags, void(*pre_fuzz_cb)(void *fuzzcxt, generic_func_t target_pc, dr_mcontext_t *mc), bool(*post_fuzz_cb)(void *fuzzcxt, generic_func_t target_pc))
 
DR_EXPORT drmf_status_t drfuzz_unfuzz_target (generic_func_t func_pc)
 
DR_EXPORT drmf_status_t drfuzz_register_fault_event (void(*event)(void *fuzzcxt, drfuzz_fault_t *fault, drfuzz_fault_ex_t *fault_ex))
 
DR_EXPORT drmf_status_t drfuzz_unregister_fault_event (void(*event)(void *fuzzcxt, drfuzz_fault_t *fault, drfuzz_fault_ex_t *fault_ex))
 
DR_EXPORT drmf_status_t drfuzz_register_fault_delete_callback (void(*callback)(void *fuzzcxt, drfuzz_fault_t *fault))
 
DR_EXPORT drmf_status_t drfuzz_unregister_fault_delete_callback (void(*callback)(void *fuzzcxt, drfuzz_fault_t *fault))
 
DR_EXPORT drmf_status_t drfuzz_register_crash_thread_event (void(*event)(void *fuzzcxt, drfuzz_fault_thread_state_t *state))
 
DR_EXPORT drmf_status_t drfuzz_unregister_crash_thread_event (void(*event)(void *fuzzcxt, drfuzz_fault_thread_state_t *state))
 
DR_EXPORT void * drfuzz_get_fuzzcxt (void)
 
DR_EXPORT void * drfuzz_get_drcontext (void *fuzzcxt)
 
DR_EXPORT drmf_status_t drfuzz_get_target_num_bbs (DR_PARAM_IN generic_func_t target_pc, DR_PARAM_OUT uint64 *num_bbs)
 
DR_EXPORT drmf_status_t drfuzz_get_arg (void *fuzzcxt, generic_func_t target_pc, int arg, bool original, DR_PARAM_OUT void **arg_value)
 
DR_EXPORT drmf_status_t drfuzz_set_arg (void *fuzzcxt, int arg, void *val)
 
DR_EXPORT drmf_status_t drfuzz_get_target_user_data (DR_PARAM_IN generic_func_t target_pc, DR_PARAM_OUT void **user_data)
 
DR_EXPORT drmf_status_t drfuzz_set_target_user_data (DR_PARAM_IN generic_func_t target_pc, DR_PARAM_IN void *user_data, DR_PARAM_IN void(*delete_callback)(void *user_data))
 
DR_EXPORT drmf_status_t drfuzz_get_target_per_thread_user_data (DR_PARAM_IN void *fuzzcxt, DR_PARAM_IN generic_func_t target_pc, DR_PARAM_OUT void **user_data)
 
DR_EXPORT drmf_status_t drfuzz_set_target_per_thread_user_data (DR_PARAM_IN void *fuzzcxt, DR_PARAM_IN generic_func_t target_pc, DR_PARAM_IN void *user_data, DR_PARAM_IN void(*delete_callback)(void *fuzzcxt, void *user_data))
 
DR_EXPORT drfuzz_target_iterator_tdrfuzz_target_iterator_start (void *fuzzcxt)
 
DR_EXPORT drfuzz_target_frame_tdrfuzz_target_iterator_next (drfuzz_target_iterator_t *iter)
 
DR_EXPORT drmf_status_t drfuzz_target_iterator_stop (drfuzz_target_iterator_t *iter)
 
DR_EXPORT drmf_status_t drfuzz_mutator_load (DR_PARAM_IN const char *lib_path, DR_PARAM_INOUT drfuzz_mutator_api_t *api)
 
DR_EXPORT drmf_status_t drfuzz_mutator_unload (DR_PARAM_IN drfuzz_mutator_api_t *lib)
 

Detailed Description

Header for Dr. Fuzz: DynamoRIO Fuzz Testing Extension.

Typedef Documentation

◆ drfuzz_crash_state_t

Records the state of all application threads at the time of a crash.

◆ drfuzz_fault_ex_t

typedef dr_siginfo_t drfuzz_fault_ex_t

Provides extended information about a critical fault. On Unix cast to dr_siginfo_t, or on Windows cast to dr_exception_t. See documentation on those structs for details.

Where provided by callbacks from this API, instances of this struct are temporary and may not be accessed after the callback function returns. Copy the struct as necessary.

◆ drfuzz_fault_t

Provides basic information about an occurrence of a "critical fault", which in drfuzz refers to a subset of signals (Unix) or exceptions (Windows) that (a) are likely to be caused by fuzz testing, (b) imply errors and/or vulnerabilities in the code of the target application, and (c) terminate execution if they are not caught and handled. By default, the set of "critical faults" is SIGSEGV and SIGBUS on Unix, and Access Violation on Windows. (In a future release, the "critical faults" will be configurable by the drfuzz client.) Also see comments on drfuzz_register_fault_event().

Where provided by callbacks from this API, this struct may be retained indefinitely. Additional information about a critical fault is provided by drfuzz_fault_ex_t, which duplicates some data from this struct, but may not be retained after a callback.

◆ drfuzz_fault_thread_state_t

Records the state of a thread at the time a fault occurred on that thread, or at the time the thread is aborted due to application crash. Faults recorded in the state at the time of a crash are not necessarily responsible for the crash.

Note
Currently only the first and last faults will be provided in the faults array.

◆ drfuzz_target_frame_t

Represents the stack frame of a fuzz target during one fuzz iteration, including the argument values from that iteration. To access the target frames for any thread, call drfuzz_target_iterator_start() from that thread. When a crash occurs, the set of target frames that were live at the time of the critical fault are copied into a drfuzz_fault_thread_state_t, which is provided in the crash events.

Note
For pointer arguments, the pointed value may change, or may no longer be accessible, after the stack frame returns (or aborts on crash). Clients requiring post-mortem access to such pointed values will need to store them at the beginning of each fuzz iteration.

◆ drfuzz_target_iterator_t

typedef void* drfuzz_target_iterator_t

An opaque iterator of fuzz targets, representing the set of targets that were live on the call stack of one thread at a specific point in time.

Function Documentation

◆ drfuzz_exit()

DR_EXPORT drmf_status_t drfuzz_exit ( void  )

Clean up all resources used by the Dr. Fuzz extension.

◆ drfuzz_fuzz_target()

DR_EXPORT drmf_status_t drfuzz_fuzz_target ( generic_func_t  func_pc,
uint  arg_count,
uint  flags,
uint  wrap_flags,
void(*)(void *fuzzcxt, generic_func_t target_pc, dr_mcontext_t *mc)  pre_fuzz_cb,
bool(*)(void *fuzzcxt, generic_func_t target_pc)  post_fuzz_cb 
)

Register the function that starts at address func_pc for repeated fuzz testing. The pre_func and post_func callbacks will control the fuzz testing cycle. The client may arbitrarily change arguments to the target function during the pre_func callback, and fuzz testing of the target will continue for as long as the post_func callback returns true.

Fuzzing requests should normally be made up front during process initialization or module load (see dr_register_module_load_event()). If a fuzzing request is made after the target code may have already been executed by the application, the caller should flush the target code from the cache using the desired flush method after issuing the fuzzing request. Multiple fuzzing requests for the same func_pc are not allowed.

The pre_func will be called at the beginning of the target function on each iteration, before any of its code executes. The pre_func may examine the arguments using drfuzz_get_arg() and modify them using drfuzz_set_arg(). Before each invocation of the pre_func, drfuzz will reset the arguments to the original values that were passed by the application (by shallow copy). Argument values may only be changed during a pre_func callback.

The post_func will be called after the target function returns on each iteration, but before any subsequent instructions following the call site have been executed. Returning true will cause drfuzz to redirect execution back to the start of the target function, adjusting the call stack and resetting the argument values accordingly (see drwrap_redirect_execution() for details). Argument accessors drfuzz_get_arg() and drfuzz_set_arg() are not available in this phase of the fuzzing cycle, though drfuzz_get_target_arg() can be used at any time during fuzzing.

The fuzzer implements repeated execution of the target function using the drwrap extension, which accepts a flags argument for each wrapped target function. Use the wrap_flags parameter to pass flags through to the internal drwrap_wrap_ex() call. The calling convention specified in the wrap_flags must be correct or the target function will have incorrect arguments and/or a corrupt stack during fuzz testing.

Note
Recursive invocation of the fuzz target is currently not supported.
Parameters
[in]func_pcThe start pc of the new fuzz target function.
[in]arg_countThe actual number of arguments passed to the fuzz target function during fuzz testing (i.e., for vararg targets, the client must know how many args are actually used).
[in]flagsReserved for future use; must be set to 0.
[in]wrap_flagsFlags for the delegated call to wrap the fuzz target function for repeated execution; see drwrap_wrap_ex().
[in]pre_fuzz_cbCalled prior to each fuzz iteration of the target function (must not be NULL). Any changes made by the callee to the application registers must be applied to the mcontext provided (or they will not take effect).
[in]post_fuzz_cbCalled following each fuzz iteration of the target function (must not be NULL).

◆ drfuzz_get_arg()

DR_EXPORT drmf_status_t drfuzz_get_arg ( void *  fuzzcxt,
generic_func_t  target_pc,
int  arg,
bool  original,
DR_PARAM_OUT void **  arg_value 
)

Get the value of an argument to the fuzz target function at target_pc. May only be called while fuzzing of this target is in progress. Will retrieve the arg value for the current fuzz iteration on the current thread. Returns DRMF_SUCCESS on success.

Parameters
[in]fuzzcxtThe drfuzz thread context.
[in]target_pcThe target function. May be NULL, which implies that the target is the most recently called target on the app call stack.
[in]argIdentifies the argument by its index.
[in]originalSpecifies whether to get the original value of the argument passed by the app, or the currently applied fuzz value.
[out]arg_valueReturns the value of the argument (when successful).

◆ drfuzz_get_drcontext()

DR_EXPORT void* drfuzz_get_drcontext ( void *  fuzzcxt)

Get the dcontext associated with this fuzzcxt.

◆ drfuzz_get_fuzzcxt()

DR_EXPORT void* drfuzz_get_fuzzcxt ( void  )

Get the drfuzz thread context for the current thread. This function has significant overhead, and should not be used repetitively in performance-sensitive applications.

◆ drfuzz_get_target_num_bbs()

DR_EXPORT drmf_status_t drfuzz_get_target_num_bbs ( DR_PARAM_IN generic_func_t  target_pc,
DR_PARAM_OUT uint64 *  num_bbs 
)

Get the total number of basic blocks seen during target_pc fuzzing, i.e., from the first execution of the target function at target_pc to the last exit from that function.

Parameters
[in]target_pcThe target function. If target_pc is NULL, the total number of basic blocks seen during execution is returned.
[out]num_bbsReturns the number of basic blocks.
Note
: The number of basic blocks returned might not be the precise number of new blocks that are a direct result of the target function's execution. For example, a basic block might be counted multiple times due to code cache management; basic blocks executed by other threads are not be counted; basic blocks executed in the inner fuzzing function are not counted for the outer fuzzing function in the case of nested fuzzing.

◆ drfuzz_get_target_per_thread_user_data()

DR_EXPORT drmf_status_t drfuzz_get_target_per_thread_user_data ( DR_PARAM_IN void *  fuzzcxt,
DR_PARAM_IN generic_func_t  target_pc,
DR_PARAM_OUT void **  user_data 
)

Get the user data associated with the specified target_pc and fuzzcxt. If the fuzzcxt is NULL, the fuzzcxt for the current thread will be used (if any).

◆ drfuzz_get_target_user_data()

DR_EXPORT drmf_status_t drfuzz_get_target_user_data ( DR_PARAM_IN generic_func_t  target_pc,
DR_PARAM_OUT void **  user_data 
)

Get the user data associated with the target_pc.

◆ drfuzz_init()

DR_EXPORT drmf_status_t drfuzz_init ( client_id_t  client_id)

Initialize the Dr. Fuzz extension. This function must be called before any other Dr. Fuzz API functions. Can be called any number of times, but each call must be paired with a corresponding call to drfuzz_exit().

◆ drfuzz_mutator_load()

DR_EXPORT drmf_status_t drfuzz_mutator_load ( DR_PARAM_IN const char *  lib_path,
DR_PARAM_INOUT drfuzz_mutator_api_t *  api 
)

Loads a mutator. If lib_path is NULL, the default mutator built in to Dr. Fuzz is loaded. Otherwise, the custom, third-party mutator library located at the file path lib_path is loaded. The mutator interface for the loaded mutator is returned in api. The caller must set api->struct_size before calling. Returns DRMF_SUCCESS on success.

◆ drfuzz_mutator_unload()

DR_EXPORT drmf_status_t drfuzz_mutator_unload ( DR_PARAM_IN drfuzz_mutator_api_t *  lib)

Unloads a custom mutator library. Returns DRMF_SUCCESS on success.

◆ drfuzz_register_crash_thread_event()

DR_EXPORT drmf_status_t drfuzz_register_crash_thread_event ( void(*)(void *fuzzcxt, drfuzz_fault_thread_state_t *state)  event)

Register to be notified of an application crash on each thread that is running at the time of the crash. The event contains the state of the current thread at the time of the fault. If the crash was not caused by this thread, the state may contain faults that would have been handled by the app (had it continued to run).

The state also contains a list of fuzz targets. If the state contains faults, these targets represent the state of fuzzing at the time the first fault occurred. Otherwise these targets were live at the time the thread was aborted by the crash.

Access the targets using the provided iterator, but do not stop the iterator (drfuzz_target_iterator_stop() will be called internally).

Note
Does not allow multiple registration.

◆ drfuzz_register_fault_delete_callback()

DR_EXPORT drmf_status_t drfuzz_register_fault_delete_callback ( void(*)(void *fuzzcxt, drfuzz_fault_t *fault)  callback)

Register to be notified when drfuzz deletes a fault object, indicating it is no longer safe to retain it. If user_data has been attached, it should be disposed at this time.

Note
Does not allow multiple registration.

◆ drfuzz_register_fault_event()

DR_EXPORT drmf_status_t drfuzz_register_fault_event ( void(*)(void *fuzzcxt, drfuzz_fault_t *fault, drfuzz_fault_ex_t *fault_ex)  event)

Register for notification of a fault event, which occurs when the execution of any fuzz target encounters a critical fault (as defined at drfuzz_fault_t). Since the app may handle the fault, drfuzz does not report it to the user at the time this event occurs. Instead, it maintains a chain of faults that occur during a single fuzz iteration, and only reports them if the application crashes before starting the next fuzz iteration. Use drfuzz_register_crash_thread_event() to receive crash notification.

Event parameters

    [in] fuzzcxt  The drfuzz thread-local context of the fault.
    [in] fault  Provides basic information about the kind and location of the fault, and may be retained by the callee until delete (to be notified, use drfuzz_register_fault_delete_callback()). The field user_data is available for attaching custom data to the fault for later use during the crash events (if any) via drfuzz_fault_thread_state_t and drfuzz_crash_state_t.
    [in] fault_ex  Provides extended information about the memory state at the fault. This struct is transitory and must be copied if any of its data needs to be retained.
Note
Does not allow multiple registration.

◆ drfuzz_set_arg()

DR_EXPORT drmf_status_t drfuzz_set_arg ( void *  fuzzcxt,
int  arg,
void *  val 
)

Set the value of an argument to the target function. May only be called from a pre-fuzz callback. Returns DRMF_SUCCESS on success.

This routine may de-reference application memory directly, so the caller should wrap it in DR_TRY_EXCEPT if crashes must be avoided.

◆ drfuzz_set_target_per_thread_user_data()

DR_EXPORT drmf_status_t drfuzz_set_target_per_thread_user_data ( DR_PARAM_IN void *  fuzzcxt,
DR_PARAM_IN generic_func_t  target_pc,
DR_PARAM_IN void *  user_data,
DR_PARAM_IN void(*)(void *fuzzcxt, void *user_data)  delete_callback 
)

Set the user data associated with the specified target_pc and fuzzcxt. If the fuzzcxt is NULL, the fuzzcxt for the current thread will be used (if any). If the delete_callback is not NULL, it will be called when drfuzz deletes the internal target data structure (after completing a fuzz pass), or when the thread exits.

Note
: Only one slot is provided for the data, so multiple writes will overwrite.

◆ drfuzz_set_target_user_data()

DR_EXPORT drmf_status_t drfuzz_set_target_user_data ( DR_PARAM_IN generic_func_t  target_pc,
DR_PARAM_IN void *  user_data,
DR_PARAM_IN void(*)(void *user_data)  delete_callback 
)

Set the user data associated with the specified target_pc. If the delete_callback is not NULL, it will be called when drfuzz deletes the internal target data structure.

Note
: Only one slot is provided for the data, so multiple writes will overwrite.

◆ drfuzz_target_iterator_next()

DR_EXPORT drfuzz_target_frame_t* drfuzz_target_iterator_next ( drfuzz_target_iterator_t iter)

Returns the next fuzz target frame in the iteration set, or NULL after the last frame.

◆ drfuzz_target_iterator_start()

DR_EXPORT drfuzz_target_iterator_t* drfuzz_target_iterator_start ( void *  fuzzcxt)

Initiates an iterator over the set of fuzz targets that are live on the current thread's call stack. Use drfuzz_target_iterator_next() to traverse the fuzz target frames, and use drfuzz_target_iterator_stop() to free the iterator and all frames.

◆ drfuzz_target_iterator_stop()

DR_EXPORT drmf_status_t drfuzz_target_iterator_stop ( drfuzz_target_iterator_t iter)

Stop a fuzz target iterator and free its allocated resources (including target frames).

◆ drfuzz_unfuzz_target()

DR_EXPORT drmf_status_t drfuzz_unfuzz_target ( generic_func_t  func_pc)

Unregister the fuzz target at func_pc from drfuzz. Future executions of the target function will not be repeated in the fuzz testing loop. Should not be called while the target function is executing (application may behave incorrectly or crash).

◆ drfuzz_unregister_crash_thread_event()

DR_EXPORT drmf_status_t drfuzz_unregister_crash_thread_event ( void(*)(void *fuzzcxt, drfuzz_fault_thread_state_t *state)  event)

Unregister the crash notification callback.

◆ drfuzz_unregister_fault_delete_callback()

DR_EXPORT drmf_status_t drfuzz_unregister_fault_delete_callback ( void(*)(void *fuzzcxt, drfuzz_fault_t *fault)  callback)

Unregister the fault delete notification callback.

◆ drfuzz_unregister_fault_event()

DR_EXPORT drmf_status_t drfuzz_unregister_fault_event ( void(*)(void *fuzzcxt, drfuzz_fault_t *fault, drfuzz_fault_ex_t *fault_ex)  event)

Unregister the fault notification event.