当前位置: 首页 > 知识库问答 >
问题:

linux-kernel - 使用kprobe监控do_filp_open函数, 参数获取失败,原因在哪里?

经兴安
2024-09-27

我使用kprobe监控do_filp_open函数, 获取参数异常,原因在哪里?

代码如下

SEC("kprobe/do_filp_open")
int do_filp_open_exit(struct  pt_regs *ctx){
        struct filename * pathname = (struct filename *)PT_REGS_PARM2(ctx);
        const struct open_flags * op = (struct open_flags *)PT_REGS_PARM3(ctx);

        if(op->open_flag & O_CREAT || op->intent & LOOKUP_CREATE) { //运行时这里报错 提示invalid mem access 'inv'
            e->type = CREATEFILE;
            __builtin_memcpy(e->event_name, "createfile", sizeof("createfile"));
        }
}

内核版本是5.4.18
我确认了内核版本的该函数的参数,并无更改

求他检测的一些函数同样使用PT_REGS_PARM3命令可以获取到函数,也排除了宏的问题。

还有什么其他的方法可以分析原因吗?

另外 我在内核5.4版本上要替换我代码中的fexit监控的函数。原本的代码是运行在6.0的 所以支持fexit,同时可以获取到参数和返回值。
在5.4版本上kretprobe只能获取返回值 ,kprobe只能获取参数 有没有其他好的探测方式?

共有1个答案

张财
2024-09-27

问题分析

在您的案例中,使用 kprobe 监控 do_filp_open 函数时遇到参数获取失败的问题,特别是在访问 op->open_flagop->intent 时出现了“invalid mem access 'inv'”错误。这通常指示了几个可能的原因:

  1. 参数地址不正确:可能 PT_REGS_PARM2(ctx)PT_REGS_PARM3(ctx) 没有正确指向预期的结构体。这可能是因为 do_filp_open 函数的参数在内核版本间发生了变化,或者宏 PT_REGS_PARM2PT_REGS_PARM3 没有正确解析参数位置。
  2. 结构体定义不一致:如果 struct filenamestruct open_flags 的定义与内核中实际使用的不同,访问这些结构体的成员时会出现问题。
  3. 编译环境问题:有时编译环境(如 GCC 版本、内核头文件等)的差异可能导致不同的行为。
  4. 内存访问权限问题:内核可能出于安全考虑,对某些内存区域施加了保护,使得用户态或特定上下文中无法直接访问。

解决方案

  1. 验证参数位置

    • 检查 do_filp_open 函数的实际参数列表,确保 PT_REGS_PARM2PT_REGS_PARM3 确实指向了正确的参数。
    • 使用 printk 或其他内核日志机制打印这些参数的地址和内容,看看它们是否有效。
  2. 检查结构体定义

    • 确认 struct filenamestruct open_flags 的定义与内核源代码中的定义一致。
    • 如果这些结构体在内核中有变动(例如,通过内核补丁或不同版本的内核),请相应地更新您的代码。
  3. 使用动态调试工具

    • 使用如 SystemTap 或 eBPF 等工具,这些工具可以在不修改内核代码的情况下进行动态跟踪和调试。
    • 这些工具可以提供关于函数参数和调用堆栈的详细信息,有助于诊断问题。
  4. 考虑内核版本差异

    • 由于您从内核 6.0 迁移到 5.4,请特别注意两个版本间内核 API 和行为的变化。
    • 如果没有 fexit 支持,您可能需要使用其他方法(如 kprobe 钩子到相关的返回点)来捕获返回值。
  5. 替代方案

    • 如果 kprobe 和 kretprobe 不能满足需求,考虑使用其他类型的内核模块,如 tracepoints(如果可用)或自定义的系统调用。
    • 编写一个内核模块,在 do_filp_open 调用前后注册回调函数,通过更直接的方式访问所需的数据。
  6. 编译和测试

    • 确保使用与内核版本相匹配的编译器和内核头文件进行编译。
    • 在目标系统上充分测试您的模块,以确保它在不同的工作负载和条件下都能稳定工作。

总结

您遇到的问题可能与参数地址不正确、结构体定义不一致、编译环境问题或内存访问权限有关。通过验证参数位置、检查结构体定义、使用动态调试工具、考虑内核版本差异以及编写替代方案,您应该能够诊断并解决这个问题。

 类似资料:
  • 问题内容: 我有以下失败部分: 我想在错误消息的正文中包含构建失败的原因。 我怎样才能做到这一点? 如果没有,是否可以将构建日志文件附加到电子邮件? 问题答案: 我不知道一种凭空自动获取故障原因的方法。 但是,您可以在每个阶段中使用“ post {failure {”块来至少捕获其失败的阶段到环境变量中(例如env.FAILURE_REASON),并在最终(全局范围)通知块中访问该env var

  • 如何获取原型链里函数的参数? Abc() 里想获取 add() 的参数。 请问要如何操作?

  • 问题内容: 是将数字转换为字符串的便捷工具。Linux似乎没有,是否有等效的功能或者我必须使用? 问题答案: 编辑:对不起,我应该记得这台机器绝对是非标准的,出于学术目的已插入了各种非标准的实现;-) 由于确实不规范,如一些有用的评论者提到的,最好使用或(更好的,因为它是从安全缓冲区溢出)。我知道它不像它那么简洁或酷,但是至少您可以编写一次,到处运行(tm);-) 这是旧的(编辑过的)答案 您正确

  • 这有什么问题: 我在这里尝试过:用不同的编译器https://godbolt.org/z/NkL44s: x86-64 gcc 9.2:编译 x86-64 gcc(主干):失败 x86-64 clang 6.0.0:编译 x86-64 clang 7.0.0及更高版本:失败 x64 msvc v19.22:编译 x64 msvc v19.23(内部测试):失败 那么,为什么最近的编译器会拒绝这一点

  • 本文向大家介绍javascript 获取函数形参个数,包括了javascript 获取函数形参个数的使用技巧和注意事项,需要的朋友参考一下

  • 我正在使用Junit4测试外部java类。我想模拟下面的代码行 我试过这样 但我仍然收到了这个错误“java.lang.ExceptionInInitializeError” Java语言lang.ExceptionInInitializerRor在sun。反映GeneratedSerializationConstructorAccessor6。java上的newInstance(未知源)。lan