深入ftrace uprobe原理和功能介绍

news2024/12/22 22:36:46

上一章我们学习了,kprobe 可以实现动态内核的注入,基于中断的方法在任意指令中插入追踪代码,并且通过 pre_handler/post_handler去接收回调。另一个 kprobe 的同族是 kretprobe,只不过是针对函数级别的内核监控,根据用户注册时提供的 entry_handlerret_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,请参考内核文档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);

此外,没有像 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 攻防中的应用

Uprobes概述和使用 - SIer,但我想做技术博客 (kimullaa.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/31061.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Arduino开发实例-RCWL0516微波雷达传感器驱动

RCWL0516微波雷达传感器驱动 接近感应是入侵警报、电灯开关以及其他家庭和工业自动化应用的常见应用。 电子工业中使用了多种接近检测方法。 最常见的方法是使用 PIR 传感器,它可以感应由温暖的身体引起的环境红外辐射的变化。 其他常见的方法包括使用反射的超声波或光束,其…

关于 SAP HANA 数据库的死锁问题(deadlock)

一个朋友在我的知识星球里提问&#xff1a; hana数据库发生死锁后&#xff0c;会自动解开吗&#xff1f;还是会等着自动超时后报错。 笔者在 15 年的 SAP 开发生涯中对 HANA 数据库接触得比较少&#xff0c;这里只能根据网络上搜索出的一些材料来回答。 首先&#xff0c;如果是…

YoC的使用

1 YoC的使用 参考地址 https://mp.csdn.net/mp_blog/analysis/article/all CB2201是基于CH2201的物联网应用开发板&#xff0c;开发板提供丰富的接口&#xff0c;满足应用的需求。基于该开发板&#xff0c;YoC 提供多种应用场景的开发示例&#xff0c;通过示例可以快速应用于…

卷出头了,终于学完阿里架构师推荐 413 页微服务分布式架构基础与实战笔记

时间飞逝&#xff0c;转眼间毕业七年多&#xff0c;从事 Java 开发也六年了。我在想&#xff0c;也是时候将自己的 Java 整理成一套体系。 这一次的知识体系面试题涉及到 Java 知识部分、性能优化、微服务、并发编程、开源框架、分布式等多个方面的知识点。 写这一套 Java 面试…

可视化大屏--响应式适配解决方案flexible.js

响应式适配解决方案flexible.js 最近公司开了第二个项目&#xff0c;是一个可视化大屏。 那么&#xff0c;在可视化大屏的基础上&#xff0c;我们肯定是要适配所有的屏幕设备&#xff0c;不能出现一换电脑&#xff0c;样式就紊乱的情况。 so,我们也不需要自己写媒体查询了&…

第40讲:MySQL索引的语法以及基本使用

文章目录1.索引的使用语法2.索引的基本使用2.1.准备一张数据表2.2.按照如下需求为表中的字段创建索引2.3.查看创建的索引2.4.删除索引3.验证使用索引前后的执行效率1.索引的使用语法 1&#xff09;创建索引 创建索引时&#xff0c;如果不指定索引的类型&#xff0c;默认就是常…

极简示例揭示 SwiftUI 中 @ObservedObject 与 @StateObject 状态的关键区别

问题现象 话说在 SwiftUI 中视图是状态的函数,这话一点都不假。正是秉性各异的各种状态构成了 SwiftUI 视图千变万化的功能。 这里,我们将为大家揭开其中两个常用状态,即 @ObservedObject 与 @StateObject 状态之间的最关键不同,并带领大家绕过实际使用中可能出现的坑: …

秋染田野稻菽飘香 国稻种芯·中国水稻节:河北各地农业丰收

秋染田野稻菽飘香 国稻种芯中国水稻节&#xff1a;河北各地农业丰收 河北日报 &#xff08;记者郝东伟&#xff09; 新闻中国采编网 中国新闻采编网 谋定研究中国智库网 中国农民丰收节国际贸易促进会 国稻种芯中国水稻节 中国三农智库网-功能性农业农业大健康大会报道&#x…

JavaIO流:模型

IO 的字面意思是读/写数据&#xff0c;IO 模型是读/写数据的方式。常用到的读/写数据方式有&#xff1a;同步阻塞 IO、同步非阻塞 IO、IO 多路复用、信号驱动、异步 IO &#xff5e; 本篇内容包括&#xff1a;Java IO 与 IO 模型、五种 IO 模型、三种 Java IO 模型。 文章目录一…

计算机组成原理期末复习第三章-2(唐朔飞)

计算机组成原理期末复习第三章-2&#xff08;唐朔飞&#xff09; ✨欢迎关注&#x1f5b1;点赞&#x1f380;收藏⭐留言✒ &#x1f52e;本文由京与旧铺原创&#xff0c;csdn首发&#xff01; &#x1f618;系列专栏&#xff1a;java学习 &#x1f4bb;首发时间&#xff1a;&am…

电子元器件企业面临缺货涨价,SRM协同系统助力企业采购数字化智慧升级

近年来&#xff0c;在移动互联网技术不断发展、消费电子产品制造水平提高和居民收入水平增加等因素的驱动下&#xff0c;电子元器件行业呈现蓬勃发展的态势。未来随着5G、物联网、人工智能、虚拟现实、新型显示等新兴技术与消费电子产品的融合&#xff0c;这会使得行业需求量持…

linux进程间通信-FIFO,让你全方位理解

有名管道(FIFO) 有名管道也被称为FIFO文件&#xff0c;是一种特殊的文件。由于linux所有的事物都可以被视为文件&#xff0c;所以对有名管道的使用也就变得与文件操作非常统一。 (1)创建有名管道 用如下两个函数中的其中一个&#xff0c;可以创建有名管道。 #include #include …

python项目上线

python项目上线一 购买服务器二 使用MobaXterm连接服务器三 上线图四 安装git五 安装mysql六 安装redis七 安装python八 安装uwsgi九 安装虚拟环境十 安装nginx十一 前端部署十二 后端部署12.1 git拉取代码&#xff0c;安装依赖12.2 配置数据库12.3 迁移数据库12.4 使用uwsgi启…

作为微软开发者官方号,我们又要做点特别的事情了

在“感谢”二字最容易说出口的日子 谢谢每一个你&#xff0c;像一颗颗星星一样 点亮 MSDN 微软开发者社区的技术宇宙 我们也将在这个最值得感谢的日子 做一点特别的事情 MSDN 到底什么来头&#xff1f; MSDN 微软开发者社区已经成立快10年了&#xff0c;相信有很多资深开发…

Android服务器的通信方式

目录 一.HTTP协议 1.简介 2.Get和Post的使用 1.Get请求 2.Post请求 3.Get请求和Post请求的区别 二.Socket Socket的使用类型主要有两种&#xff1a; 客户端&#xff1a; 三.Socket 与 Http 对比 Android与服务器的通信方式主要有两种&#xff0c;一是Http通信&#xf…

Docker安装Gitlab-ruuner

第一步 # 拉取镜像 docker pull gitlab/gitlab-runner:latest # 启动容器 docker run -d --name gitlab-runner --restart always -v /opt/gitlab-runner/config:/etc/gitlab-runner -v /var/run/docker.sock:/var/run/docker.sock gitlab/gitlab-runner:latest 第二步 查看/…

Windows 上修改 docker 的镜像文件存储位置(修改 WSL 文件映射)

Windows 上修改 docker 的镜像文件存储位置&#xff08;修改 WSL 文件映射&#xff09;1、起因2、修改2.1 关闭 Docker Desktop2.2 备份镜像2.3 WSL 取消注册 docker-desktop-data2.4 镜像数据导回 WSL 并挂载到新路径3、验证1、起因 一开始在 Windows 上安装了 docker 后&…

运动用品品牌排行榜,2022年值得买的运动用品推荐

如今&#xff0c;人们的生活节奏越来越快&#xff0c;工作和生活压力大。因此&#xff0c;人们越来越重视体育运动&#xff0c;通过体育运动达到放松和锻炼身体的目的&#xff0c;运动装备也就跟着火热起来。无论是进行室内或户外活动&#xff0c;选一套合适的运动装备是很有必…

【java】java 类型安全 与 unchecked warning

1.概述 1.1. What does type-safety mean? 我的总结: 从概念上来说,Type Safety,最本质上,就是对于内存(Memory)的“正确访问”。假如说,在内存的一块区域上存储着一个String类型的对象;按照正常的逻辑,这块内存区域就应该被当作String来进行处理,这就是所谓的“…

MASA Framework 事件总线 - 进程内事件总线

概述 事件总线是一种事件发布/订阅结构&#xff0c;通过发布订阅模式可以解耦不同架构层级&#xff0c;同样它也可以来解决业务之间的耦合&#xff0c;它有以下优点 松耦合横切关注点可测试性事件驱动 发布订阅模式 通过下图我们可以快速了解发布订阅模式的本质 订阅者将自…