Linux模块:有关任务创建和销毁的通知 [英] Linux module: being notified about task creation and destruction

查看:103
本文介绍了Linux模块:有关任务创建和销毁的通知的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于Linux上的Mach内核API仿真,我需要在刚创建任务或终止任务时调用我的内核模块.

for Mach kernel API emulation on Linux, I need for my kernel module to get called when a task has been just created or is being terminated.

在我的内核模块中,这可以很好地通过Linux安全模块来完成,但是几年前,它们通过取消导出所需的符号来阻止外部模块充当LSM.

In my kernel module, this could most nicely be done via Linux Security Modules, but a couple of years ago, they prevented external modules from acting as a LSM by unexporting the needed symbols.

我能找到的唯一另一种方法是使我的模块像rootkit一样工作.找到系统调用表并将其钩在那里.​​

The only other way I could find was to make my module act like a rootkit. Find the syscall table and hook it in there.

修补内核是不可能的.我需要轻松安装我的应用程序.还有其他办法吗?

Patching the kernel is out of the question. I need my app to be installed easily. Is there any other way?

推荐答案

您可以使用 Kprobes ,它使您能够动态地挂接到内核中的代码中.您将需要在创建和销毁可为您提供所需信息的过程中找到合适的功能.例如,对于创建的任务,fork.c中的do_fork()将是一个不错的起点.对于已销毁的任务,请执行do_exit.您可能想编写一个retprobe,这是一种kprobe,它在函数执行结束之前还可以在返回之前为您提供控制.您希望在函数返回之前进行控制的原因是,通过检查返回值来检查函数是否成功创建了进程.如果发生错误,则该函数将返回负值,在某些情况下可能返回0.

You can use Kprobes, which enables you to dynamically hook into code in the kernel. You will need to find the right function among the ones involves in creating and destroying processes that give you the information you need. For instance, for tasks created, do_fork() in fork.c would be a good place to start. For tasks destroyed, do_exit. You would want to write a retprobe, which is a kind of kprobe that additionally gives you control at the end of the execution of the function, before it returns. The reason you want control before the function returns is to check if it succeeded in creating the process by checking the return value. If there was an error, then the function will return a negative value or in some cases possibly 0.

您可以通过创建一个kretprobe结构来实现:

You would do this by creating a kretprobe struct:

static struct kretprobe do_fork_probe = {
    .entry_handler = (kprobe_opcode_t *) my_do_fork_entry,
    .handler = (kprobe_opcode_t *) my_do_fork_ret,
    .maxactive = 20,
    .data_size = sizeof(struct do_fork_ctx)
};

当控制进入钩子函数时,

my_do_fork_entry被执行,而my_do_fork_ret在返回之前就被执行.您可以按如下所示将其连接:

my_do_fork_entry gets executed when control enters the hooked function, and my_do_fork_ret gets executed just before it returns. You would hook it in as follows:

do_fork_probe.kp.addr =
    (kprobe_opcode_t *) kallsyms_lookup_name("do_fork");

if ((ret = register_kretprobe(&do_fork_probe)) <0) {
    // handle error
}

在实现钩子的过程中,获取参数和返回值有点笨拙.您可以通过保存的寄存器pt_regs数据结构来获取它们.让我们看一下返回挂钩,在x86上,您可以通过regs-> ax获得返回值.

In the implementation of your hooks, it's a bit unwieldy to get the arguments and return value. You get these via the saved registers pt_regs data structure. Let's look at the return hook, where on x86 you get the return value via regs->ax.

static int my_do_fork_ret(struct kretprobe_instance *ri, struct pt_regs *regs)
{
    struct do_fork_ctx *ctx = (struct do_fork_ctx *) ri->data;
    int ret = regs->ax; // This is on x86
    if (ret > 0) {
        // It's not an error, probably a valid process
    }
}

在入口点,您可以通过寄存器访问参数.例如在x86上,regs-> di是第一个参数,regs-> si是第二个参数,等等.请注意,您不应该依赖这些寄存器作为返回挂钩中的参数,因为这些寄存器可能已被其他计算覆盖.

In the entry point, you can get access to the arguments via the registers. e.g. on x86, regs->di is the first argument, regs->si is the second etc. You can google to get the full list. Note that you shouldn't rely on these registers for the arguments in the return hook as the registers may have been overwritten for other computations.

为确保此功能正常运行,您肯定会跳出很多麻烦,但希望此说明能使您朝正确的方向前进.

You will surely have to jump many hoops in getting this working, but hopefully this note should set you off in the right direction.

这篇关于Linux模块:有关任务创建和销毁的通知的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆