且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Linux模块:有关任务创建和销毁的通知

更新时间:2023-07-27 18:30:04

您可以使用 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.