Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Store extra data in a c function pointer

Suppose there is a library function (can not modify) that accept a callback (function pointer) as its argument which will be called at some point in the future. My question: is there a way to store extra data along with the function pointer, so that when the callback is called, the extra data can be retrieved. The program is in c.

For example:

// callback's type, no argument
typedef void (*callback_t)();  

// the library function            
void regist_callback(callback_t cb);       

// store data with the function pointer
callback_t store_data(callback_t cb, int data);

// retrieve data within the callback
int retrieve_data();

void my_callback() {
    int a;
    a = retrieve_data();
    // do something with a ...
}

int my_func(...) {
    // some variables that i want to pass to my_callback
    int a;

    // ... regist_callback may be called multiple times
    regist_callback(store_data(my_callback, a));
    // ...
}

The problem is because callback_t accept no argument. My idea is to generate a small piece of asm code each time to fill into regist_callback, when it is called, it can find the real callback and its data and store it on the stack (or some unused register), then jump to the real callback, and inside the callback, the data can be found.

pseudocode:

typedef struct {
    // some asm code knows the following is the real callback
    char trampoline_code[X]; 
    callback_t real_callback;
    int data;       
} func_ptr_t;

callback_t store_data(callback_t cb, int data) {
    // ... malloc a func_ptr_t
    func_ptr_t * fpt = malloc(...);

    // fill the trampoline_code, different machine and
    // different calling conversion are different
    // ...

    fpt->real_callback = cb;
    fpt->data = data;

    return (callback_t)fpt;
}

int retrieve_data() {
    // ... some asm code to retrive data on stack (or some register)
    // and return
}

Is it reasonable? Is there any previous work done for such problem?

like image 604
jayven Avatar asked Apr 25 '26 11:04

jayven


1 Answers

Unfortunately you're likely to be prohibited from executing your trampoline in more and more systems as time goes on, as executing data is a pretty common way of exploiting security vulnerabilities.

I'd start by reporting the bug to the author of the library. Everybody should know better than to offer a callback interface with no private data parameter.

Having such a limitation would make me think twice about how whether or not the library is reentrant. I would suggest ensuring you can only have one call outstanding at a time, and store the callback parameter in a global variable.

If you believe that the library is fit for use, then you could extend this by writing n different callback trampolines, each referring to their own global data, and wrap that up in some management API.

like image 182
sh1 Avatar answered Apr 27 '26 02:04

sh1



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!