我试图拦截系统调用以改变其中一些的行为。我使用 LKM 以下描述的内容:http: //syprog.blogspot.co.uk/2011/10/hijack-linux-system-calls-part-iii.html。
但是,在为某些系统调用执行此操作时,我遇到了一些问题,例如:
/* original sys_clone pointer */
asmlinkage long (*real_clone)(unsigned long,
unsigned long,
void* __user,
void* __user,
struct pt_regs*);
/* sys_clone replacement */
asmlinkage long custom_clone(unsigned long clone_flags,
unsigned long newsp,
void* __user parent_tid,
void* __user child_tid,
struct pt_regs *regs)
{
return real_clone(clone_flags, newsp, parent_tid, child_tid, regs);
}
创建分段错误。
/* original sys_delete_module pointer */
asmlinkage long (*real_delete_module)(const char* __user, unsigned int);
/* sys_delete_module replacement */
asmlinkage long custom_delete_module(const char* __user name_user,
unsigned int flags){
return real_delete_module(name_user, flags);
}
这会在 system_call_fastpath(错误的 RIP 值)中生成“无法处理内核分页请求”。
系统调用在 sys_call_table 中被这样修改:
// get sys_call_table address
make_rw((unsigned long)sys_call_table);
real_clone = (void*)sys_call_table[ __NR_clone];
sys_call_table[ __NR_clone] = (unsigned long *)custom_clone;
// etc...
make_ro((unsigned long)sys_call_table);
并在模块卸载时放回:
make_rw((unsigned long)sys_call_table);
sys_call_table[ __NR_clone] = (unsigned long *)real_clone;
make_ro((unsigned long)sys_call_table);
这可能是非常简单的事情,但我真的不明白。拦截对 open、mkdir 或 exit 的调用没有问题,但我无法真正理解其他一些原因问题,因为替换只是调用原始函数。
编辑:它在调用时失败,而不是在初始化期间。
EDIT2:我找到了使用 kprobe 的“解决方案”。鉴于我只想使用子进程 pid 的 do_fork(在 sys_clone 中实际调用的)的返回值,如果我想更改 sys_clone 的行为,它实际上不会因为明显的原因而工作。将此用作参考http://www-users.cs.umn.edu/~boutcher/kprobes/
实际的解决方案如下:
static int ret_do_fork_handler(struct kretprobe_instance *ri,
struct pt_regs *regs)
{
pid_t ppid, cpid;
ppid = current->pid;
cpid = (pid_t)regs->ax;
if(cpid < 0){
printk("do_fork returned an error");
return 0;
}else{
printk("do_fork process %lu\n", (unsigned long)ppid);
printk("do_fork returns %lu\n", (unsigned long)cpid);
}
return 0;
}
static struct kretprobe do_fork_kretprobe = {
.handler = ret_do_fok_handler,
.maxactive = 500, // some random value
.kp = {
.symbol_name = "do_fork",
}
};
在模块初始化中:
if ((retval = register_kretprobe(&do_fork_kretprobe)) < 0) {
printk(KERN_ERR "register_kretprobe failed, returned %d\n",
retval);
return -1;
}
注销模块时:
unregister_kretprobe(&my_kretprobe);