首页 > 其他分享 >ftrace uprobe原理和功能

ftrace uprobe原理和功能

时间:2024-04-30 15:36:16浏览次数:26  
标签:kernel ftrace tracing ret handler 内核 原理 uprobe

原文:https://blog.csdn.net/u012489236/article/details/127954817
官网:https://www.kernel.org/doc/html/latest/trace/uprobetracer.html

kprobe 可以实现动态内核的注入,基于中断的方法在任意指令中插入追踪代码,并且通过 pre_handler/post_handler去接收回调。另一个 kprobe 的同族是 kretprobe,只不过是针对函数级别的内核监控,根据用户注册时提供的 entry_handler 和 ret_handler 来分别在函数进入时和返回前进行回调。

uprobe ,顾名思义,相对于内核函数/地址的监控,主要用于用户态函数/地址的监控。听起来是不是有点神奇,内核怎么监控用户态函数的调用呢?本章的内容包括:

如何使用uprobe
内核是如何通过uprobe监控用户态的调用,其原理是如何的
1 如何使用uprobe
站在用户视角,我们先看个简单的例子,假设有这么个一个用户程序:

// test.c
#include <stdio.h>
void foo() {
    printf("hello, uprobe!\n");
}
int main() {
    foo();
    return 0;
}

编译好之后,查看某个符号的地址,然后告诉内核我要监控这个地址的调用:

#gcc test.c -o test
#readelf -s test | grep foo
    56: 000000000000115a    19 FUNC    GLOBAL DEFAULT   14 foo
#echo 1 > /sys/kernel/debug/tracing/events/uprobes/p_test_0x115a/enable
#echo 1 > /sys/kernel/debug/tracing/events/uprobes/p_test_0x115a/enable
#echo 1 > /sys/kernel/debug/tracing/tracing_on

然后运行用户程序并检查内核的监控返回:

$ ./test && ./test
hello, uprobe!
hello, uprobe!

 对于内核如何使用uprobe,请参考内核文档 https://www.kernel.org/doc/html/latest/trace/uprobetracer.html,其使用基本跟kprobe类似

 

2 实现原理

上面的接口是基于 tracefs,即读写文件的方式去与内核交互实现 uprobe 监控。

 其中写入 uprobe_events 时会经过一系列内核调用,最终会调用到create_or_delete_trace_uprobe

 

对于__trace_uprobe_create跟使用kprobe类似,也是大家使用的三板斧

  • **alloc_trace_uprobe:**分配 uprobe 结构体

 

**register_trace_uprobe:**注册 uprobe:

regiseter_uprobe_event: 将 probe 添加到全局列表中,并创建对应的 uprobe debugfs 目录,即上文示例中的 p_test_0x115a

对于uprobe其实整个流程跟kprobe基本类似,我们重点关注于uprobe_register的函数做了些什么

 当已经注册了 uprobe 的 ELF 程序被执行时,可执行文件会被 mmap 映射到进程的地址空间,同时内核会将该进程虚拟地址空间中对应的 uprobe 地址替换成断点指令。

 

 

与 kprobe 类似,我们可以在触发 uprobe 时候根据对应寄存器去提取当前执行的上下文信息,比如函数的调用参数等。同时 uprobe 也有类似的同族: uretprobe。

通过设置uprobe,我们来看看通过gdb跟踪后,反汇编对应的文件,对于x86平台是不是修改成int3指令,确实是修改成int3指令

 

指定位置上的指令,头部修改为软件中断指令(同时原指令存档他处):

  1. 当执行到该位置时,触发软件中断,陷入内核
  2. 在内核,执行以 注入的 Handler
  3. 单步执行原指令
  4. 修正寄存器和栈,回到原有指令流

3 uprobe内核模块验证

我们以ubuntu为试验环境,使用uprobe一般都是编写内核驱动,在模块中定义uprobe_consumer ,然后调用uprobe的API(uprobe_register)来进行注册uprobe

#include <linux/module.h>
#include <linux/ptrace.h>
#include <linux/uprobes.h>
#include <linux/namei.h>
#include <linux/moduleparam.h>

MODULE_AUTHOR("john doe");
MODULE_LICENSE("GPL v2");

static char *filename;
module_param(filename, charp, S_IRUGO);

static long offset;
module_param(offset, long, S_IRUGO);

static int handler_pre(struct uprobe_consumer *self, struct pt_regs *regs){
        pr_info("handler: arg0 = %d arg1 =%d \n", (int)regs->di, (int)regs->si);
        return 0;
}

static int handler_ret(struct uprobe_consumer *self,
                                unsigned long func,
                                struct pt_regs *regs){
        pr_info("ret_handler ret = %d \n", (int)regs->ax);
        return 0;
}

static struct uprobe_consumer uc = {
        .handler = handler_pre,
        .ret_handler = handler_ret,
};


static struct inode *inode;

static int __init uprobe_init(void) {
        struct path path;
        int ret;

        ret = kern_path(filename, LOOKUP_FOLLOW, &path);
        if (ret < 0) {
                pr_err("kern_path failed, returned %d\n", ret);
                return ret;
        }

        inode = igrab(path.dentry->d_inode);
        path_put(&path);

        ret = uprobe_register(inode, offset, &uc);
        if (ret < 0) {
                pr_err("register_uprobe failed, returned %d\n", ret);
                return ret;
        }

        return 0;
}

static void __exit uprobe_exit(void) {
        uprobe_unregister(inode, offset, &uc);
}

module_init(uprobe_init);
module_exit(uprobe_exit);
View Code

此外,没有像 Kprobes 那样提供 uretprobe_register,如果 ret_handler 设置为值,则设置uretprobe,生成Makefile

obj-m := hello-uprobe-world.o
KDIR    := /lib/modules/$(shell uname -r)/build
VERBOSE = 0

all:
        $(MAKE) -C $(KDIR) M=$(PWD) KBUILD_VERBOSE=$(VERBOSE) CONFIG_DEBUG_INFO=y modules
clean:
        rm -f *.o *.ko *.mod.c Module.symvers modules.order

编译生成ko文件:

 

准备要跟踪的程序:

#include <stdio.h>

int add(int a, int b) {
        return a + b;
}

int main(void) {
        add(1, 2);
}

安装ko文件,并执行该文件,我们跟踪add函数,其offset可以通过获取

 

4 uprobe_event验证

uprobe_events 是一种无需创建内核模块即可使用 Uprobe 的机制。 您可以在与 Ftrace 相同的界面中动态创建探测

root@rlk:/sys/kernel/tracing# echo 'p:sample_uprobe /root/Make/main:0x114a %di %si' >  /sys/kernel/debug/tracing/uprobe_events
root@rlk:/sys/kernel/tracing# echo 'r:sample_uretprobe /root/Make/main:0x114a %ax' >>  /sys/kernel/debug/tracing/uprobe_events
root@rlk:/sys/kernel/tracing# echo 1 > /sys/kernel/tracing/events/uprobes/sample_uprobe/enable
root@rlk:/sys/kernel/tracing# echo 1 > /sys/kernel/tracing/events/uprobes/sample_uretprobe/enable

查看结果:

 

5 perf_event_open
perf_event_open系统调用将 BPF 程序附加到 uprobe 事件。 直接编写 BPF 程序可能比较痛苦,因此需要通过 bpftrace 来使用它。

bpftrace -e ‘uretprobe:/root/work/uprobe/main:add {printf(“%d\n”, retval); exit(); }’

 检查perf_event_open的使用方式

 

6 参考文档

Linux 内核监控在 Android 攻防中的应用:https://evilpan.com/2022/01/03/kernel-tracing/#uprobe

https://www.kernel.org/doc/html/latest/trace/uprobetracer.html

标签:kernel,ftrace,tracing,ret,handler,内核,原理,uprobe
From: https://www.cnblogs.com/shiqi17/p/18168095

相关文章

  • 云原生二十篇|Kubernetes核心原理
    本文主要介绍k8s的核心原理,包括浅析各个模块的运行逻辑和k8s中的网络通讯。第一部分:模块 <imgsrc="https://pic2.zhimg.com/v2-795889f97336ebfcb89bed1e712ed0a1_b.jpg"data-caption=""data-size="normal"data-rawwidth="1080"data-rawheight="488"......
  • 预习二 原理协议与结构
    -原理是指一种普遍适用于某个领域的基本原则、规律或理论。在计算机科学中,原理可以指算法、数据结构、操作系统、编程语言等方面的基本原则。-协议是指通信双方(或多方)之间为了进行有序、可靠、高效的通信而达成的一组规定和约定。在计算机网络中,协议用于规定不同设备之间的数据传......
  • Mysql锁机制与优化实践以及MVCC底层原理剖析
    学习来源-图灵课堂https://vip.tulingxueyuan.cn锁学习参考:https://juejin.cn/post/7307889500545253395  锁机制为了保证数据的一致性,当访问共享变量的时候我们可以针对共享数据加锁,但是加锁要时要注意加锁的成本,还有加锁的粒度,还有就是是否会发生死锁,还有就是发生了死锁......
  • 阴影贴图原理
    https://blog.csdn.net/u013929284/article/details/131498349https://github.com/Zack921/visual-demo/tree/main/webgl/examples/shadow利用阴影贴图实现阴影1.利用离屏绘制拿到阴影纹理(1)把绘制目标切换到帧缓冲区(2)将视点转换到光源上,绘制时把片元的z值写入色值,得到深......
  • 边缘计算原理与六大应用介绍
    边缘计算概述边缘计算使数据存储和处理靠近生成或收集数据的位置,而不是在位于数千公里的服务器上。它将通过保持灵活性在边缘无缝可靠地部署服务。它比云计算更安全,因为不需要传输数据。因此,在将数据从边缘移动到云端时,不用担心数据丢失。因此,它提供了更快的洞察力和商业利益,减少......
  • 层次分析法(AHP)计算原理解释
    AHP层次分析法是一种解决多目标复杂问题的定性和定量相结合进行计算决策权重的研究方法。该方法将定量分析与定性分析结合起来,用决策者的经验判断各衡量目标之间能否实现的标准之间的相对重要程度,并合理地给出每个决策方案的每个标准的权数,利用权数求出各方案的优劣次序,比较有效地......
  • 熵权(值)法计算权重原理解释&综合得分纵向对比
    熵值是不确定性的一种度量。信息量越大,不确定性就越小,熵也就越小;信息量越小,不确定性越大,熵也越大。因而利用熵值携带的信息进行权重计算,结合各项指标的变异程度,利用信息熵这个工具,计算出各项指标的权重,为多指标综合评价提供依据。权重计算熵值法的计算公式如下:参考文献:[1]张晓......
  • Mysql事务原理与优化最佳实践
    学习来源-图灵课堂https://vip.tulingxueyuan.cn说到MySQL的innodb的一大特性,就不得不说到事务。今天就学习事务。事务事务的定义:逻辑上的一组操作,要么一起成功,要么一起失败,中间绝对不会存在别的状态。逻辑上的一组操作,就是说这些操作都是有逻辑关系的。我们通常说的事务是针......
  • 原理图与PCB设计
    原理图与PCB制作1PCB(印刷电路板)介绍2嘉立创EDA安装和配置EDA:工程命名:一般是名称加-版本号(v0.0.1)_日期3PCB快速入门3.1原理图绘制1.搜索元器件(Shift+F或者底部“库”菜单)2.放置元器件3.元器件摆放4.连线(快捷默认Alt+W,改为W)5.翻转、调整6.DRC检查3......
  • 支持向量机的算法原理与Python实现
    支持向量机(SupportVectorMachine,SVM)是一种强大的监督学习算法,用于分类和回归任务。其核心思想是在高维空间中找到一个最优的超平面,将不同类别的数据分开。SVM的关键在于找到支持向量,即离超平面最近的数据点,这些支持向量决定了超平面的位置和方向。SVM通过最大化支持向量与超平面......