6. KEDR Reference

6.1. API for Payload Modules
6.1.1. Header file
6.1.2. struct kedr_repl_table
6.1.3. struct kedr_payload
6.1.4. kedr_payload_register()
6.1.5. kedr_payload_unregister()
6.1.6. kedr_target_module_in_init()
6.1.7. A Stub of a Payload Module

6.1. API for Payload Modules

This section describes the interface that the KEDR core provides for payload modules. Technically, the API is provided by kedr-base module.

Important

When interacting with the KEDR core, the payload modules should rely only on the API described here. Other types, functions, macros, constants, etc., that can be found in the headers and the source files of KEDR system are for internal use only and subject to change.

6.1.1. Header file

The API is declared in the header file that a payload module should #include:

#include <kedr/base/common.h>

6.1.2. struct kedr_repl_table

struct kedr_repl_table represents a replacement table that defines which replacement function should be called instead of each particular target function in the module under analysis.

struct kedr_repl_table
{
    void** orig_addrs; 
    void** repl_addrs; 
    unsigned int num_addrs;
};

orig_addrs - an array of the addresses of target functions (what to replace).

repl_addrs - an array of addresses of replacement functions (with what to replace).

num_addrs - number of elements to process in each of the two arrays above.

Each payload module has usually a single global instance of this structure (see the example in Section 6.1.3, “struct kedr_payload”).

Note

There are no additional restrictions on the names of replacement functions. The KEDR core will use their addresses rather than the names.

6.1.3. struct kedr_payload

struct kedr_payload represents a payload module from the point of view of the KEDR core.

struct kedr_payload
{
    struct module* mod;
    struct kedr_repl_table repl_table;
    void (*target_load_callback)(struct module*);
    void (*target_unload_callback)(struct module*);
};

mod - the payload module itself. This field is usually initialized with THIS_MODULE value.

repl_table - the replacement table.

target_load_callback and target_unload_callback. If not NULL, these callbacks are called by KEDR core after the target module is loaded (but before it begins its initialization) and, respectively, when the target module has done cleaning up and is about to unload. The callbacks are passed the pointer to the target module as an argument. If a callback is NULL, it is ignored.

Note

Note that if the target module fails to initialize itself (and its init function returns an error as a result) and target_unload_callback is not NULL, this callback will be called nevertheless.

Each payload module has usually a single global instance of struct kedr_payload structure and passes its address when registering and unregistering itself with the KEDR core.

Example:

/* Addresses of the functions of interest (target functions) */
static void* orig_addrs[] = {
    (void*)&_copy_to_user,
    (void*)&_copy_from_user
};

/* Addresses of the replacement functions */
static void* repl_addrs[] = {
    (void*)&repl__copy_to_user,
    (void*)&repl__copy_from_user
};

static struct kedr_payload payload = {
    .mod                    = THIS_MODULE,
    .repl_table.orig_addrs  = &orig_addrs[0],
    .repl_table.repl_addrs  = &repl_addrs[0],
    .repl_table.num_addrs   = ARRAY_SIZE(orig_addrs),
    .target_load_callback   = NULL,
    .target_unload_callback = NULL
};

6.1.4. kedr_payload_register()

int 
kedr_payload_register(struct kedr_payload* payload);

This function registers a payload module with the KEDR core.

payload is the address of the kedr_payload instance identifying the payload module (see Section 6.1.3, “struct kedr_payload”).

The function returns 0 if successful, an error code otherwise (the general rules of the kernel functions apply here too).

The function is usually called in the init function of the payload module.

6.1.5. kedr_payload_unregister()

void 
kedr_payload_unregister(struct kedr_payload* payload);

This function unregisters the payload module from the KEDR core. After this is done, KEDR no longer uses this payload module (unless it registers itself again).

payload should be the same address as it was in the corresponding call to kedr_payload_register().

The function is usually called in the cleanup (exit) function of the payload module.

6.1.6. kedr_target_module_in_init()

int
kedr_target_module_in_init(void);

This function returns nonzero if the target module is currently loaded and is executing its init function at the moment, 0 otherwise.

In fact, the function just checks whether the target module has already dropped its .init.* sections (what the modules do after they have completed their initialization). Therefore the function will always return 0 if the init function was not marked as __init in the target module. This should not be a big problem though.

This function can be useful to implement particular fault simulation scenarios (like fail everything after init), etc.

Note however that there is a chance that the target module will complete its initialization after kedr_target_module_in_init() has determined that the target is in init but before the return value of kedr_target_module_in_init() is used. It is up to the user of the target module to ensure that no request is made to the module until its initialization is properly handled.

It is allowed to call this function from atomic context.

6.1.7. A Stub of a Payload Module

Here is what a simple payload module may look like (this is a stub rather than a real module, of course).

/*********************************************************************
 * Module: stub_payload
 * 
 * Target kernel functions: 
 * 
 *   unsigned long kfoo(void *) 
 *   void* kbar(void *, unsigned int) 
 *   int kbaz(void)
 *
 * The replacement functions provided by this module have the same 
 * signatures as the respective target functions but different names.
 *********************************************************************/
#include <linux/module.h>
#include <linux/init.h>

MODULE_AUTHOR("<Some name here>");
MODULE_LICENSE("<Some license here>");
/*********************************************************************/

#include <kedr/base/common.h>
/* #include other necessary header files here */

/*********************************************************************
 * Replacement functions
 *********************************************************************/
static unsigned long
repl_kfoo(void *arg)
{
    unsigned long returnValue;
    
    /* Call the target function (optional)*/
    returnValue = kfoo(arg);
    
    /* Process the results if necessary, dump data to a trace, etc. */
    /* ... */

    /* What the replacement function should return is also up to the provider
     * of the function. Here, it is the return value of the target function 
     * but, generally, it is not mandatory.
     */
    return returnValue;
}

static void*
repl_kbar(void *arg, unsigned int n)
{
/* The replacement function is not required to call the target function at 
 * all. It is up to the provider of the replacement function.
 */
    if (n >= SOME_THRESHOLD) {
        return NULL; /* this may simulate a failure */
    } else {
        return kbar(arg, n);
    }
}

static int
repl_kbaz(void)
{
/* The replacement function is not required to do anything at all. */
    return 777;
}

/*********************************************************************/

/* Addresses of the functions of interest (target functions) */
static void* orig_addrs[] = {
    (void*)&kfoo,
    (void*)&kbar,    
    (void*)&kbaz
};

/* Addresses of the replacement functions */
static void* repl_addrs[] = {
    (void*)&repl_kfoo,
    (void*)&repl_kbar,    
    (void*)&repl_kbaz
};

static struct kedr_payload payload = {
    .mod                    = THIS_MODULE,
    .repl_table.orig_addrs  = &orig_addrs[0],
    .repl_table.repl_addrs  = &repl_addrs[0],
    .repl_table.num_addrs   = ARRAY_SIZE(orig_addrs),
    .target_load_callback   = NULL,
    .target_unload_callback = NULL
};
/*********************************************************************/

static void
stub_payload_cleanup_module(void)
{
    kedr_payload_unregister(&payload);
    /* do other cleanup work */
    return;
}

static int __init
stub_payload_init_module(void)
{
    /* initialize other necessary facilities */
    return kedr_payload_register(&payload);
}

module_init(kedr_cm_user_space_access_init_module);
module_exit(stub_payload_cleanup_module);
/*********************************************************************/