我想在do_execve上设置一个jprobe钩子来捕获每个执行的程序。
我的代码是工作在<= 3.2 linux内核(debian)。这是我在linux内核3.2上的输出:
[ 628.534037] registered: do_execve, ret: 0
[ 723.995797] execve: /usr/bin/vi
[ 726.807025] execve: /bin/dmesg
在4.1内核I上得到相同的结果(所有内容都已注册),但没有"execve":
[ 8621.430568] registered: do_execve, ret: 0
这是我的代码:
static struct jprobe jprobe_hooks[] = {
{
.entry = jdo_execve,
.kp = { .symbol_name = "do_execve" }
}};
static long jdo_execve(const char *filename, const char __user *const __user *argv, const char __user *const __user *envp, struct pt_regs *regs)
{
printk(KERN_INFO "execve: %s", filename );
}
//
// registration
//
int ret, x, reg_error;
reg_error = 0;
for (x = 0; x < sizeof(jprobe_hooks) / sizeof(jprobe_hooks[0]); x++)
{
ret = register_jprobe(&jprobe_hooks[x]);
if (ret < 0)
{
printk(KERN_INFO "register_jprobe failed, returned %d, item: %sn", ret, jprobe_hooks[x].kp.symbol_name);
reg_error++;
}
else
{
printk(KERN_INFO "registered: %s, ret: %un", jprobe_hooks[x].kp.symbol_name, ret);
}
}
当我在kallsyms上执行grep时,我得到3.2:
grep do_execv /proc/kallsyms
ffffffff81100650 T do_execve
和on 4.2:
grep do_execv /proc/kallsyms
ffffffff811d2950 T do_execve
ffffffff811d2980 T do_execveat
我甚至试图改变函数(因为do_execve原型已经改变):
static int jdo_execve(struct filename *fname, const char __user *const __user *__argv, const char __user *const __user *__envp)
{
int i = 0;
printk(KERN_INFO "execve: %s ", fname->name );
}
即使这样也没有帮助。
我可以在do_fork或sys_open等函数上设置钩子,但不能在do_execve上设置钩子。为什么?有人有想法吗?为什么它不工作了?
编辑:我还钩子do_execveat:
static int jdo_execveat(int fd, struct filename *fname, const char __user *const __user *__argv, const char __user *const __user *__envp, int flags)
有几个问题可能会阻止您探查消息:
- 您没有以换行符结束打印消息
printk(KERN_INFO "execve: %s", filename );
,因此您的日志缓冲区没有刷新。 - API发生变化。现在
do_execve
的文件名参数为struct filename
。 - 你的jprobe代码是愚蠢的:你没有模块入口,jprobe例程必须以
jprobe_return()
调用结束等等。查看位于"samples/kprobes" 的内核源代码树中的示例
试着修复它,也许会有帮助。
无论如何,我自己试过了——这里是代码——事情确实看起来很奇怪。当我加载模块时,它注册了2个jprobe -一个用于do_execve,另一个用于do_execveat。但是当我执行程序时,我没有看到任何消息。但是我看到的是像这样的周期性消息:
jprobe: execve: /usr/lib/systemd/systemd-cgroups-agent
这意味着jprobe本身工作,但不是每个execve
调用。
所以我写了一个简单的C程序来调用execve
,只是为了确保它真的被调用了,我仍然什么也没发生,除了systemd-cgroups-agent。