views:

848

answers:

5

Hi,

Im getting into kernel work for a bit of my summer research. We are looking to make modifications to the TCP, in specific RTT calculations. What I would like to do is replace the resolution of one of the functions in tcp_input.c to a function provided by a dynamically loaded kernel module. I think this would improve the pace at which we can develop and distribute the modification.

The function I'm interested in was declared as static, however I've recompiled the kernel with the function non-static and exported by EXPORT_SYMBOL. This means the function is now accessible to other modules/parts of the kernel. I have verified this by "cat /proc/kallsyms".

Now I'd like to be able to load a module that can rewrite the symbol address from the initial to my dynamically loaded function. Similarly, when the module is to be unloaded, it would restore the original address. Is this a feasible approach? Do you all have suggestions how this might be better implemented?

Thanks!

Same as Overriding functionality with modules in Linux kernel

Edit:
This was my eventual approach.
Given the following function (which I wanted to override, and is not exported):

static void internal_function(void) 
{
  // do something interesting
  return;
}

modify like so:

static void internal_function_original(void)
{
  // do something interesting
  return;
}

static void (*internal_function)(void) = &internal_function_original;
EXPORT_SYMBOL(internal_function);

This redefines the expected function identifier instead as a function pointer (which can be called in a similar manner) pointing to the original implementation. EXPORT_SYMBOL() makes the address globally accessible, so we can modify it from a module (or other kernel location).

Now you can write a kernel module with the following form:

static void (*original_function_reference)(void);
extern void (*internal_function)(void);

static void new_function_implementation(void)
{
  // do something new and interesting
  // return
}

int init_module(void)
{
  original_function_reference = internal_function;
  internal_function           = &new_function_implementation;
  return 0;
}

void cleanup_module(void)
{
  internal_function = original_function_reference;
}

This module replaces the original implementation with a dynamically loaded version. Upon unloading, the original reference (and implementation) is restored. In my specific case, I provided a new estimator for the RTT in TCP. By using a module, I am able to make small tweaks and restart testing, all without having to recompile and reboot the kernel.

+1  A: 

I'm not sure that'll work - I believe the symbol resolution for the internal calls to the function you want to replace will have already been done by the time your module loads.

Instead, you could change the code by renaming the existing function, then creating a global function pointer with the original name of the function. Initialise the function pointer to the address of the internal function, so the existing code will work unmodified. Export the symbol of the global function pointer, then your module can just change its value by assignment at module load and unload time.

caf
I ended up going the route you suggested in adding a global hook. It was easy to implement and provided exactly what I needed.Thanks for the information regarding symbol resolution. I hadn't found a source that definitively explained how and when the symbol table was accessed (at each function call or only at linkage). This was a useful piece of advice.
Willi Ballenthin
A: 

I think what you want is Kprobe.

Another way that caf has mentioned is to add a hook to the original routine, and register/unregister hook in the module.

arsane
Kprobe looks like a interesting and useful tool. Thanks for the link.Although I took a different route, I think this could have been an effective approach.
Willi Ballenthin
+3  A: 

You can try using ksplice - you don't even need to make it non static.

bdonlan
A: 

@Willi Ballenthin

I work also on a TCP modification in the Linux kernel and would exactly need the same approach as you. Could you please post some hints how you have realized that?

armin.a
I've got it!@cafThanks for your advice!!!
armin.a
updated initial post explaining approach i eventually took. looks like i was just a few hours late ;-)
Willi Ballenthin
This is exactly what I did and it works like a charm! Although your post was a bit too late I'm sure someone else will be pleased about it! Anyway, thanks!
armin.a
A: 
kmm