I need to replace a standard system call (e.g. SYS_mkdir) with my own implementation.
As I read in some sources, including this question on Stackoverflow, the sys_call_table
is not exported symbol since kernel version 2.6
.
I tried the following code:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/unistd.h>
#include <asm/syscall.h>
int (*orig_mkdir)(const char *path);
....
int init_module(void)
{
orig_mkdir=sys_call_table[__NR_mkdir];
sys_call_table[__NR_mkdir]=own_mkdir;
printk("sys_mkdir replaced\n");
return(0);
}
....
Unfortunately I receive compiler error:
error: assignment of read-only location ‘sys_call_table[83]’
How can I replace the system call?
EDIT: Is there any solution without kernel patching?
The problem is caused due to the fact that sys_call_table is read only. In order to avoid the error, before manipulating the sys_call_table, you have to make it writable as well. The kernel provides a function to achieve it. And that function is given as set_mem_rw().
Just add the below code snippet before manipulating the sys_call_table
In the exit function of the kernel module,please do not forget to revert back the sys_call_table back to read only.It can be achieved as below.
this works for me.
See Linux Kernel: System call hooking example and https://bbs.archlinux.org/viewtopic.php?id=139406
Yes there is a solution without patching/rebuilding the kernel. Use the Kprobes infrastructure (or SystemTap).
This will allow you to place "probes" (functions) at any point(s) within the kernel, using a kernel module.
Doing similar stuff by modifying the sys_call_table is now prevented (it's read-only) & is considered a dirty hack! Kprobes/Jprobes/etc are a "clean" way to do so..Also, the documentation and samples provided in the kernel source tree is excellent (look under the kernel src tree- Documentation/kprobes.txt).
First, you need to determine the location of sys_call_table. See here.
Before writing into the just located system table, you have to make its memory pages writable. For that check here and if that doesn't work, try this.
Use LSM infrustructure.
Look at LSM hooks
path_mkdir
orinode_mkdir
for details. One question that needs to be solved is how to register your own LSM module while the system don't allow it explicitly. See the answer for details here:How can I implement my own hook function with LSM?