blob: bde1d0d466025b560a7d26711bff296105dd0b2e [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2013-2021 Google, Inc. All rights reserved.
* Copyright (c) 2010 VMware, 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 VMware, 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 VMWARE, 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_PROBE_H_
#define _DR_PROBE_H_ 1
/****************************************************************************
* Probe API
*/
/**
* @file dr_probe.h
* @brief Support for the Probe API.
*
* Describes all the data types and functions associated with the \ref
* API_probe.
*/
#ifdef __cplusplus
extern "C" {
#endif
#ifndef DR_API
# define DR_API
#endif
/**
* Describes the status of a probe at any given point. The status is returned
* by dr_register_probes() in the dr_probe_desc_t structure for each probe
* specified. It can be obtained for individual probes by calling
* dr_get_probe_status().
*/
typedef enum {
/* Error codes. */
/** Exceptions during callback execution and other unknown errors. */
DR_PROBE_STATUS_ERROR = 1,
/** An invalid or unknown probe ID was specified with dr_get_probe_status(). */
DR_PROBE_STATUS_INVALID_ID = 2,
/* All the invalid states listed below may arise statically (at the
* time of parsing the probes, i.e., inside dr_register_probes() or
* dynamically (i.e., when modules are loaded or unloaded)).
*/
/** The numeric virtual address specified for the probe insertion location
* or the callback function is invalid.
*/
DR_PROBE_STATUS_INVALID_VADDR = 3,
/** The pointer to the name of the library containing the probe insertion
* location or the callback function is invalid or the library containing
* the callback function can't be loaded.
*/
DR_PROBE_STATUS_INVALID_LIB = 4,
/** The library offset for either the probe insertion location or the
* callback function is invalid; for ex., if the offset is out of bounds.
*/
DR_PROBE_STATUS_INVALID_LIB_OFFS = 5,
/** The pointer to the name of the exported function, where the probe is to
* be inserted or which is the callback function, is invalid or the exported
* function doesn't exist.
*/
DR_PROBE_STATUS_INVALID_FUNC = 6,
/* Codes for pending cases, i.e., valid probes haven't been inserted
* because certain events haven't transpired.
*/
/** The numeric virtual address specified for the probe insertion location
* or the callback function isn't executable. This may be so at the time
* of probe registration or latter if the memory protections are changed.
* An inserted probe might reach this state if the probe insertion point or
* the callback function is made non-executable after being executable.
*/
DR_PROBE_STATUS_VADDR_NOT_EXEC = 7,
/** The library where the probe is to be inserted isn't in the process. */
DR_PROBE_STATUS_LIB_NOT_SEEN = 8,
/** Execution hasn't reached the probe insertion point yet. This is valid
* for Code Manipulation mode only because in that mode probes are inserted
* only in the dynamic instruction stream.
*/
DR_PROBE_STATUS_WAITING_FOR_EXEC = 9,
/** Either the library where the probe is to be inserted has been unloaded
* or the library containing the callback function has been unloaded.
*/
DR_PROBE_STATUS_LIB_UNLOADED = 10,
/* Miscellaneous status codes. */
/** Probe was successfully inserted. */
DR_PROBE_STATUS_INJECTED = 11,
/** One or more aspects of the probe aren't supported as of now. */
DR_PROBE_STATUS_UNSUPPORTED = 12,
#ifdef DYNAMORIO_INTERNAL
/* DON'T CHANGE THE VALUES OF THE DR_* CONSTANTS DEFINED ABOVE. They are
* exported to clients, whereas constants in this ifdef aren't. Any change
* to those values will likely break old clients with newer versions of DR
* (backward compatibility). New status codes should go after
* DR_PROBE_STATUS_UNSUPPORTED.
*/
/* Note: constants are numbered to prevent the compiler from resetting the
* sequence based on the symbolic assignments below. HOTP_INJECT_DETECT
* ended up getting the same number as one the values above! Ditto with
* HOTP_INJECT_OFF. Though these duplications only broke the tools build
* they can cause subtle runtime errors, so forcing numbers.
*/
/* The constants below are used only for LiveShields. */
/* Defines the current injection status of a policy, i.e., was it injected
* or not, why and why not? Today we don't distinguish the reasons for
* error cases, i.e., all of them are rolled into one.
*
* Constants list from most important status to least, from a reporting
* point of view; don't change this arbitrarily.
*
* CAUTION: Any changes to this will break drview, so they must be kept in
* sync.
*/
/* Deactivation, exception, error, etc. */
HOTP_INJECT_ERROR = DR_PROBE_STATUS_ERROR,
/* Completely injected in protect mode. */
HOTP_INJECT_PROTECT = DR_PROBE_STATUS_INJECTED,
/* Completely injected in detect mode. Not applicable to probes as they
* don't have detectors. Restart numbering at 100 to give enough room for
* future probe status constants.
*/
HOTP_INJECT_DETECT = 100,
/* One or more patch points in a vulnerability have been patched, but not
* all, yet. N/A to probes as they can't group multiple patch points.
*/
HOTP_INJECT_IN_PROGRESS = 101,
/* Vulnerability was matched and is ready for injection, but no patch point
* has been seen yet.
*/
HOTP_INJECT_PENDING = DR_PROBE_STATUS_WAITING_FOR_EXEC,
/* Vulnerability hasn't been matched yet. May mean that it is not yet
* vulnerable (because all dlls haven't been loaded) or just not vulnerable
* at all; there is no way to distinguish between the two.
*/
HOTP_INJECT_NO_MATCH = DR_PROBE_STATUS_LIB_NOT_SEEN,
/*
TODO: must distinguish between no match & vulnerable vs. no match & not
vulnerable; future work if needed.
HOTP_INJECT_NO_MATCH_VULNERABLE,
HOTP_INJECT_NO_MATCH_NOT_VULNERABLE,
*/
HOTP_INJECT_OFF = 102 /* Policy has been turned off, so no injection. */
#endif /* DYNAMORIO_INTERNAL */
} dr_probe_status_t;
/** Specifies what type of computation to use when computing the address of a
* probe insertion point or callback function.
*/
typedef enum {
/** Use the raw virtual address specified. */
DR_PROBE_ADDR_VIRTUAL,
/** Compute address by adding the offset specified to the base of the
* library specified.
*
* For probe insertion, if library isn't loaded, the insertion will be
* aborted. For computing callback function address if the library isn't
* loaded, it will be loaded and then the address computation will be done;
* if it can't be loaded, probe request is aborted.
*/
DR_PROBE_ADDR_LIB_OFFS,
/** Compute address by getting the address of the specified exported
* function from the specified library.
*
* If the exported function specified isn't available either for the probe
* insertion point or for the callback function, the probe insertion is
* aborted. For computing callback function address if the library isn't
* loaded, it will be loaded and then the address computation will be done;
* if it can't be loaded, probe request is aborted. */
DR_PROBE_ADDR_EXP_FUNC,
} dr_probe_addr_t;
/** Defines the location where a probe is to be inserted or callback function
* defined as an offset within a library. */
typedef struct {
/** IN - Full name of the library. */
/* FIXME PR 533522: explicitly specify what type of name should be used
* here: full path, dr_module_preferred_name(), pe (exports) name, what?
* seems broken since need full path to load a lib but that won't match?
*/
char *library;
/** IN - Offset to use inside library. If out of bounds of library, probe
* request is aborted. Offset can point to non text location as long as it
* is marked executable (i.e., ..x). */
app_rva_t offset;
} dr_probe_lib_offs_t;
/** Defines the location where a probe is to be inserted or callback function
* defined as an exported function within a library. */
typedef struct {
/** IN - Full name of the library. */
/* FIXME PR 533522: explicitly specify what type of name should be used
* here: full path, dr_module_preferred_name(), pe (exports) name, what?
* seems broken since need full path to load a lib but that won't match?
*/
char *library;
/** IN - Name of exported function inside library. If the function can't
* be found in the library, then this probe request is aborted. */
char *func;
} dr_probe_exp_func_t;
/** Defines a memory location where a probe is to be inserted or where a
* callback function exists. One of three types of address computation as
* described by dr_probe_addr_t is used to identify the location.
*/
typedef struct {
/** IN - Specifies the type of address computation to use. */
dr_probe_addr_t type;
union {
/** IN - Raw virtual address in the process space. */
app_pc vaddr;
/** IN - Library offset in the process space. */
dr_probe_lib_offs_t lib_offs;
/** IN - Exported function in the process space. */
dr_probe_exp_func_t exp_func;
};
} dr_probe_location_t;
/* TODO: hotp_exec_status_t in hotpatch_interface.h is what's really used
* in the code so once we start adding actual values here we should merge
* the two.
*/
/**
* Specifies what action to take upon return of a probe callback function.
* Additional options will be added in future releases.
*/
typedef enum {
/** Continue execution normally after the probe. */
DR_PROBE_RETURN_NORMAL = 0,
} dr_probe_return_t;
/**
* This structure describes the characteristics of a probe. It is used to add,
* update, and remove probes using dr_register_probes().
*/
typedef struct {
/**
* IN - Pointer to the name of the probe. This string does not need
* to be persistent beyond the call to dr_register_probes(): a copy will
* be made.
*/
char *name;
/**
* IN - Location where the probe is to be inserted. If inserting inside a
* library, the insertion will be done only if the library is loaded, the
* location falls within its bounds and the location is marked executable.
* If inserting outside a library the memory location should be allocated
* and marked executable. If neither, the probe will be put in a pending
* state where its id will be NULL and its status reflecting the state.
*/
dr_probe_location_t insert_loc;
/**
* IN - Location of the callback function. If callback is inside a
* library, the library location will be used if it is within its bounds
* and is marked executable; if library isn't loaded, an attempt will be
* made to load it. If using a raw virtual address, then that location
* should be mapped and marked executable. If neither is true, the probe
* insertion or update will be aborted and status updated accordingly.
*
* The callback function itself should have this signature:
*
* dr_probe_return_t probe_callback(priv_mcontext_t *mc);
*
* Note that the \p xip field of the \p priv_mcontext_t passed in will
* NOT be set.
*/
dr_probe_location_t callback_func;
/** OUT - Upon successful probe insertion a unique id will be created. */
unsigned int id;
/** OUT - Specifies the current status of the probe. */
dr_probe_status_t status;
} dr_probe_desc_t;
/******************************************************************************/
DR_API
/**
* Allows the caller to insert probes into specified executable memory
* locations in the process address space. Upon subsequent execution of
* instructions at these memory locations the appropriate probes will be
* triggered and the corresponding callback functions will be invoked.
* Subsequent calls to dr_register_probes() will allow the caller to remove,
* update and add more probes.
*
* @param probes Pointer to an array of probe descriptors of type
* dr_probe_desc_t. Each descriptor describes the
* location of the probe, the callback function and other
* data. This is an in/out parameter, see dr_probe_desc_t
* for details. If probes isn't NULL, points to valid
* memory and num_probes is greater than 0, id and status
* for each probe are set in the corresponding
* dr_probe_desc_t. If probes is NULL or num_probes is 0,
* nothing is set in probes. Invalid memory may trigger
* an exception.
*
* @param [in] num_probes Specifies the number of probe descriptors in
* the array pointed to by probes.
*
* \remarks
* If a probe definition is invalid, it will not be registered, i.e. DynamoRIO
* will not retain its definition. The error code will be returned in the
* status field in of that probe's dr_probe_desc_t element and the
* corresponding id field in dr_probe_desc_t is set to NULL.
*
* \remarks
* When a client calls dr_register_probes() from dr_client_main() (which is the
* earliest dr_register_probes() can be called), not all valid probes are
* guaranteed to be inserted upon retrun from dr_register_probes(). Some
* valid probes may not be inserted if the target module has not been loaded,
* the insertion point is not executable, or the memory is otherwise
* inaccessible. In such cases, DynamoRIO retains all valid probe
* information and inserts these probes when the memory locations become
* available.
*
* \remarks
* When dr_register_probes() is called after dr_client_main(), the behavior is
* identical to being called from dr_client_main() with one caveat: even valid probes
* aren't guaranteed to be registered when dr_register_probes() returns.
* However, valid probes will be registered within a few milliseconds usually.
* To prevent performance and potential deadlock issues, it is recommended
* that a client shouldn't wait in a loop till the probe status changes.
* Instead, clients should check probe status at a later callback.
*
* \remarks
* A client can determine the status of a registered probe in one of two ways.
* 1) Read it from the status field in the associated dr_probe_desc_t element
* when dr_register_probes() returns, or 2) call dr_get_probe_status() with
* the id of the probe.
*
* \remarks
* To add, remove or update currently registered probes dr_register_probes()
* should be called again with a new set of probe definitions. The new list
* of probes completely replaces the existing probes. That is, existing
* probes not specified in the new list are removed from the process.
*
* \remarks
* The probe insertion address has limitations. 5 bytes beginning at the start
* of a probe insertion address should have specific characteristics. No
* instruction should straddle this start of this region, i.e., the probe
* insertion address should be the beginning of an instruction. Also, no flow
* of control should jump into the middle of this 5 byte region beginning at
* the probe insertion address. Further, there should be no int instructions
* in this region. call and jump instructions are allowed in this region as
* long as they don't terminate before the end of the region, i.e., no other
* instruction should start after them in this region (as it will allow
* control flow to return to the middle of this region). If these rules are
* not adhered to the results are be unspecified; may result in process crash.
* The above mentioned restrictions hold only when using \ref API_probe not
* when using API_BT or both simultaneously.
*
* \remarks
* If only the \ref API_probe is used 5 bytes starting at the probe insertion
* address will be modified. If the process will read this memory then the
* probe should be moved to another location or removed to avoid unknown
* changes in process behavior. If the client will read this memory, then it
* has to do so before requesting probe insertion.
*
* \see dr_get_probe_status().
*/
void
dr_register_probes(dr_probe_desc_t *probes, unsigned int num_probes);
DR_API
/** Used to get the current status of a probe.
*
* \param[in] id Unique identifier of the probe for which status is desired.
*
* \param[out] status Pointer to user allocated data of type dr_probe_status_t
* in which the status of the probe specified by id is
* returned. If id matches and status isn't NULL, the
* status for the matching probe is returned. If id
* doesn't match or if status is NULL, nothing is
* returned in status.
*
* \return If id matches and status is copied successfully, 1 is returned,
* else 0 is returned.
*/
int
dr_get_probe_status(unsigned int id, dr_probe_status_t *status);
#ifdef __cplusplus
}
#endif
#endif /* _DR_PROBE_H_ */