There was a need to write a kernel module, with a hook for exec. I found a way with sys_calls_table
and lsm
. As I understand it, sys_calls_table
is more of a hack than a correct solution, and I did not find normal examples for lsm
.
How to correctly intercept a system call in modern kernel versions? I will be very happy with examples.
CodePudding user response:
There is no correct way to do this.
LSM (Linux Security Modules) doesn't support system calls interception, with LSMs you need the implemented some of the functions listed at lsm_hooks_defs.h.
There are two alternatives ways to intercept system calls which I'm aware of:
Hook the
sys_call_table
which can be obtained, and overwrite the pointers with your new function:unsigned long *sys_call_table_ptr = kallsyms_lookup_name("sys_call_table"); unsigned long cr0 = read_cr0(); write_cr0(cr0 & ~x86_CR0_WP); sys_call_table_ptr[__NR_getpid] = new_getpid; write_cr0(cr0);
Using kprobe: Syscall functions name expands with the prefix
__do_sys_
(see __SYSCALL_DEFINEx). For example, kprobe on__do_sys_finit_module
(or any other syscall you want) as follow:static struct kprobe kp = { .symbol_name = "__do_sys_finit_module", }; static int handler_pre(struct kprobe *p, struct pt_regs *regs) { // do your logic // obtain function arguments using register (calling convetion) } static int __init kprobe_init(void) { kp.pre_handler = handler_pre; ret = register_kprobe(&kp); if (ret < 0) { printk(KERN_INFO "register_kprobe failed, returned %d\n", ret); return ret; } printk(KERN_INFO "Planted kprobe at %p\n", kp.addr); return 0; } static void __exit kprobe_exit(void) { unregister_kprobe(&kp); printk(KERN_INFO "kprobe at %p unregistered\n", kp.addr); }