Without getting into the details of why, I\'m looking for a clean (as possible) way to replace kernel functions and system calls from a loadable module. My initial
This might prove a useful read to you.
Basically, since the system call table is not directly exported in newer kernels, you have to do some searching to determine its location yourself. Then you can intercept your system calls of choice and manipulate them. Replacing other kernel functions, though, will be much more difficult, unless some of them are organized the same way system calls are (they appear on some dispatch table etc.) - which is not at all common.
You probably want to hook the system calls (PDF link), which would effectively let you log user-processes calling kernel functions. If you really want to log the kernel use of kernel functions, you want to look into kernel function trace.
Since you want to only log the calls (i.e. you will not actually override them), and a small amount of changes to the kernel code is acceptable, the cleanest way would be to add a hook to each function you are interested in (using a notifier chain or even a plain function pointer). Your module then simply registers itself to all the hooks you added (and unregisters from them when unloaded).
It is also quite possible that someone else has already done the work of adding the hooks for you.
I'm not entirely sure I understand what you want to do, but I think that ksplice may be a good solution. It's still under development, so I don't know if it's in any sort of usable condition right now.
According to KernelTrap.org you can do a simple patch and recompile of your kernel to export the sys_call_table variable:
// add the following in the file arch/i386/kernel/i386_ksyms.c
extern void* sys_call_table[];
EXPORT_SYMBOL(sys_call_table);
Then just follow this procedure for replacing system calls from the Linux Kernel Module Programming Guide:
The source code here is an example of such a kernel module. We want to 'spy' on a certain user, and to
printk()
a message whenever that user opens a file. Towards this end, we replace the system call to open a file with our own function, calledour_sys_open
. This function checks the uid (user's id) of the current process, and if it's equal to the uid we spy on, it callsprintk()
to display the name of the file to be opened. Then, either way, it calls the originalopen()
function with the same parameters, to actually open the file.The
init_module
function replaces the appropriate location insys_call_table
and keeps the original pointer in a variable. Thecleanup_module
function uses that variable to restore everything back to normal. This approach is dangerous, because of the possibility of two kernel modules changing the same system call. Imagine we have two kernel modules, A and B. A'sopen
system call will beA_open
and B's will beB_open
. Now, when A is inserted into the kernel, the system call is replaced withA_open
, which will call the originalsys_open
when it's done. Next, B is inserted into the kernel, which replaces the system call withB_open
, which will call what it thinks is the original system call,A_open
, when it's done.
Most filesystem work is done in modules already, presuming that the filesystem code was built as a module, rather than built into the kernel (which means the 'real' answer depends on kernel build options).
Assuming that the bits you want to log are all filesystem-related, and that those filesystem routines are built as modules, you should just be able to alter the filesystem module(s) you're interested in, and reload them.
If those assumptions aren't true, or can't be made true, then things clearly get trickier, and I really couldn't point you much further.