blob: 6f6bb8fcec7900dce5ce8cccca01a46f750da5ea [file] [log] [blame]
/* **************************************************************
* Copyright (c) 2015 Google, Inc. All rights reserved.
* **************************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of Google, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
#ifndef _DR_FUZZ_H_
#define _DR_FUZZ_H_ 1
/* Dr. Fuzz: DynamoRIO Fuzz Testing Extension */
/* Framework-shared headers */
#include "drmemory_framework.h"
#include "drwrap.h"
#include "drfuzz_mutator.h" /* for drfuzz_mutator_t */
/**
* @file drfuzz.h
* @brief Header for Dr. Fuzz: DynamoRIO Fuzz Testing Extension
*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* \addtogroup drfuzz Dr. Fuzz: DynamoRIO Fuzz Testing Extension
*/
/*@{*/ /* begin doxygen group */
/**
* 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.
*/
typedef struct _drfuzz_target_frame_t {
app_pc func_pc; /* the target function */
uint arg_count; /* the number of arguments for this target */
reg_t *arg_values; /* the argument values */
} drfuzz_target_frame_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.
*/
typedef void * drfuzz_target_iterator_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.
*/
typedef struct _drfuzz_fault_t {
/**
* Signal number (Unix) or exception code (Windows).
*/
int fault_code;
/**
* The address within the target application where the fault occurred.
*/
app_pc fault_pc;
/**
* For memory access faults only, the address of the failed access attempt.
*/
byte *access_address;
/**
* The thread that executed the fault.
*/
thread_id_t thread_id;
/**
* Available for custom user data. To free the custom data when drfuzz deletes an
* instance of #drfuzz_fault_t, use drfuzz_register_fault_delete_callback().
*/
void *user_data;
} drfuzz_fault_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.
*/
#ifdef UNIX
typedef dr_siginfo_t drfuzz_fault_ex_t;
#else
typedef dr_exception_t drfuzz_fault_ex_t;
#endif
/**
* 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 \p faults array.
*/
typedef struct _drfuzz_fault_thread_state_t {
/**
* The thread ID.
*/
thread_id_t thread_id;
/**
* The number of critical faults that occurred in the chain, starting with the
* first fault that occurred while executing a fuzz target, and including all
* faults that occurred until the thread exited.
*/
uint faults_observed;
/**
* The number of elements in the faults array.
*/
uint fault_count;
/**
* The array of faults.
*/
drfuzz_fault_t *faults;
/**
* An iterable list of the fuzz targets that were live on the call stack when the
* first fault in the chain occurred (innermost stack frame first).
*/
drfuzz_target_iterator_t *targets;
} drfuzz_fault_thread_state_t;
/**
* Records the state of all application threads at the time of a crash.
*/
typedef struct _drfuzz_crash_state_t {
uint thread_count; /**< The number of states in the \p thread_states array. */
drfuzz_fault_thread_state_t **thread_states; /**< An array of thread states. */
} drfuzz_crash_state_t;
DR_EXPORT
/**
* 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().
*/
drmf_status_t
drfuzz_init(client_id_t client_id);
DR_EXPORT
/**
* Clean up all resources used by the Dr. Fuzz extension.
*/
drmf_status_t
drfuzz_exit(void);
DR_EXPORT
/**
* Register the function that starts at address \p func_pc for repeated fuzz testing.
* The \p pre_func and \p post_func callbacks will control the fuzz testing cycle.
* The client may arbitrarily change arguments to the target function during the
* \p pre_func callback, and fuzz testing of the target will continue for as long as
* the \p 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 \p func_pc are not allowed.
*
* The \p pre_func will be called at the beginning of the target function on each
* iteration, before any of its code executes. The \p pre_func may examine the
* arguments using drfuzz_get_arg() and modify them using drfuzz_set_arg(). Before each
* invocation of the \p 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 \p pre_func callback.
*
* The \p 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
* \p wrap_flags parameter to pass flags through to the internal drwrap_wrap_ex() call.
* The calling convention specified in the \p 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.
*
* @param[in] func_pc The start pc of the new fuzz target function.
* @param[in] arg_count The 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).
* @param[in] flags Reserved for future use; must be set to 0.
* @param[in] wrap_flags Flags for the delegated call to wrap the fuzz target
* function for repeated execution; see drwrap_wrap_ex().
* @param[in] pre_fuzz_cb Called 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).
* @param[in] post_fuzz_cb Called following each fuzz iteration of the target
* function (must not be NULL).
*/
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
/**
* 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).
*/
drmf_status_t
drfuzz_unfuzz_target(generic_func_t func_pc);
DR_EXPORT
/**
* 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.
*
* <b>Event parameters</b>
* <table border="0">
* <tr>
* <td valign="top"><code>&nbsp;&nbsp;&nbsp;&nbsp;[in]</code></td>
* <td valign="top"><b>fuzzcxt&nbsp;</b></td>
* <td valign="top">The drfuzz thread-local context of the fault.</td>
* </tr>
* <tr>
* <td valign="top"><code>&nbsp;&nbsp;&nbsp;&nbsp;[in]</code></td>
* <td valign="top"><b>fault&nbsp;</b></td>
* <td valign="top">
* 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.
* </td>
* </tr>
* <tr>
* <td valign="top"><code>&nbsp;&nbsp;&nbsp;&nbsp;[in]</code></td>
* <td valign="top"><b>fault_ex&nbsp;</b></td>
* <td valign="top">
* 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.
* </td>
* </tr>
* </table>
*
* \note Does not allow multiple registration.
*/
drmf_status_t
drfuzz_register_fault_event(void (*event)(void *fuzzcxt,
drfuzz_fault_t *fault,
drfuzz_fault_ex_t *fault_ex));
DR_EXPORT
/**
* Unregister the fault notification event.
*/
drmf_status_t
drfuzz_unregister_fault_event(void (*event)(void *fuzzcxt,
drfuzz_fault_t *fault,
drfuzz_fault_ex_t *fault_ex));
DR_EXPORT
/**
* 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.
*/
drmf_status_t
drfuzz_register_fault_delete_callback(void (*callback)(void *fuzzcxt,
drfuzz_fault_t *fault));
DR_EXPORT
/**
* Unregister the fault delete notification callback.
*/
drmf_status_t
drfuzz_unregister_fault_delete_callback(void (*callback)(void *fuzzcxt,
drfuzz_fault_t *fault));
DR_EXPORT
/**
* 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.
*/
drmf_status_t
drfuzz_register_crash_thread_event(void (*event)(void *fuzzcxt,
drfuzz_fault_thread_state_t *state));
DR_EXPORT
/**
* Unregister the crash notification callback.
*/
drmf_status_t
drfuzz_unregister_crash_thread_event(void (*event)(void *fuzzcxt,
drfuzz_fault_thread_state_t *state));
DR_EXPORT
/**
* Get the drfuzz thread context for the current thread. This function has significant
* overhead, and should not be used repetitively in performance-sensitive applications.
*/
void *
drfuzz_get_fuzzcxt(void);
DR_EXPORT
/**
* Get the dcontext associated with this fuzzcxt.
*/
void *
drfuzz_get_drcontext(void *fuzzcxt);
DR_EXPORT
/**
* Get the total number of basic blocks seen during \p target_pc fuzzing,
* i.e., from the first execution of the target function at \p target_pc
* to the last exit from that function.
*
* @param[in] target_pc The target function. If \p target_pc is NULL, the total
* number of basic blocks seen during execution is returned.
* @param[out] num_bbs Returns 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.
*/
drmf_status_t
drfuzz_get_target_num_bbs(IN generic_func_t target_pc, OUT uint64 *num_bbs);
DR_EXPORT
/**
* Get the value of an argument to the fuzz target function at \p 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.
*
* @param[in] fuzzcxt The drfuzz thread context.
* @param[in] target_pc The target function. May be NULL, which implies that the target
* is the most recently called target on the app call stack.
* @param[in] arg Identifies the argument by its index.
* @param[in] original Specifies whether to get the original value of the argument
* passed by the app, or the currently applied fuzz value.
* @param[out] arg_value Returns the value of the argument (when successful).
*/
drmf_status_t
drfuzz_get_arg(void *fuzzcxt, generic_func_t target_pc, int arg, bool original,
OUT void **arg_value);
DR_EXPORT
/**
* 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.
*/
drmf_status_t
drfuzz_set_arg(void *fuzzcxt, int arg, void *val);
DR_EXPORT
/**
* Get the user data associated with the \p target_pc.
*/
drmf_status_t
drfuzz_get_target_user_data(IN generic_func_t target_pc, OUT void **user_data);
DR_EXPORT
/**
* Set the user data associated with the specified \p target_pc. If the \p 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.
*/
drmf_status_t
drfuzz_set_target_user_data(IN generic_func_t target_pc, IN void *user_data,
IN void (*delete_callback)(void *user_data));
DR_EXPORT
/**
* Get the user data associated with the specified \p target_pc and \p fuzzcxt. If the
* \p fuzzcxt is NULL, the fuzzcxt for the current thread will be used (if any).
*/
drmf_status_t
drfuzz_get_target_per_thread_user_data(IN void *fuzzcxt, IN generic_func_t target_pc,
OUT void **user_data);
DR_EXPORT
/**
* Set the user data associated with the specified \p target_pc and \p fuzzcxt. If the
* \p fuzzcxt is NULL, the fuzzcxt for the current thread will be used (if any). If the
* \p 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.
*/
drmf_status_t
drfuzz_set_target_per_thread_user_data(IN void *fuzzcxt, IN generic_func_t target_pc,
IN void *user_data,
IN void (*delete_callback)(void *fuzzcxt,
void *user_data));
DR_EXPORT
/**
* 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_t *
drfuzz_target_iterator_start(void *fuzzcxt);
DR_EXPORT
/**
* Returns the next fuzz target frame in the iteration set, or NULL after the last frame.
*/
drfuzz_target_frame_t *
drfuzz_target_iterator_next(drfuzz_target_iterator_t *iter);
DR_EXPORT
/**
* Stop a fuzz target iterator and free its allocated resources (including target frames).
*/
drmf_status_t
drfuzz_target_iterator_stop(drfuzz_target_iterator_t *iter);
/***************************************************************************
* Mutation
*/
typedef struct _drfuzz_mutator_api_t {
size_t struct_size;
dr_auxlib_handle_t handle;
# define DYNAMIC_INTERFACE 1
# include "drfuzz_mutator.h"
# undef DYNAMIC_INTERFACE
} drfuzz_mutator_api_t;
DR_EXPORT
/**
* Loads a mutator. If \p lib_path is NULL, the default mutator built
* in to \p Dr. Fuzz is loaded. Otherwise, the custom, third-party
* mutator library located at the file path \p lib_path is loaded.
* The mutator interface for the loaded mutator is returned in \p api.
* The caller must set \p api->struct_size before calling. Returns
* DRMF_SUCCESS on success.
*/
drmf_status_t
drfuzz_mutator_load(IN const char *lib_path, INOUT drfuzz_mutator_api_t *api);
DR_EXPORT
/**
* Unloads a custom mutator library. Returns DRMF_SUCCESS on success.
*/
drmf_status_t
drfuzz_mutator_unload(IN drfuzz_mutator_api_t *lib);
/*@}*/ /* end doxygen group */
#ifdef __cplusplus
}
#endif
#endif /* _DR_FUZZ_H_ */