首页 > 其他分享 >转载-奇小葩- 深入ftrace uprobe原理和功能介绍

转载-奇小葩- 深入ftrace uprobe原理和功能介绍

时间:2023-05-29 17:11:21浏览次数:60  
标签:ftrace 奇小葩 int tracing ret handler 内核 uprobe

原文链接:https://blog.csdn.net/u012489236/article/details/127954817

 

上一章我们学习了,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)

Uprobe-tracer: Uprobe-based Event Tracing

 

标签:ftrace,奇小葩,int,tracing,ret,handler,内核,uprobe
From: https://www.cnblogs.com/stellarbin/p/17441038.html

相关文章

  • 转载-奇小葩- linux性能工具--ftrace使用
    原文链接:https://blog.csdn.net/u012489236/article/details/119519361 Ftrace设计作为一个内部的tracer提供给系统的开发者和设计者,帮助他们弄清kernel正在发生的行为,它能够调式分析延迟和性能问题。对于前一章节,我们学习了Ftrace发展到现在已经不仅仅是作为一个functiontr......
  • 转载-奇小葩-linux性能工具--ftrace框架
    原文链接:https://blog.csdn.net/u012489236/article/details/119494200 对于ftrace架构,主要来了解下内核是如何实现的,其主要包括如下内容:ringbuffer的原理和代码分析tracer(function、function_graph、irq_off)原理和代码分析traceevent1.ringBufferRingbuffer是......
  • tracer ftrace笔记(17)——atrace命令抓trace
    一、atrace命令解析1.帮助信息#atrace-h用法:usage:atrace[options][categories...]选项包括:-aappname为逗号分隔的cmdlines列表启用应用程序级跟踪;*是匹配任何进程的通配符-bN使用大小为NKB的跟踪缓冲区-c......
  • 时延检测利器-uftrace
    本文来自博客园,作者:T-BARBARIANS,转载请注明原文链接:https://www.cnblogs.com/t-bar/p/16898892.html 谢谢!篇幅较长,阅读耗时告警!一、前言作为后台程序的开......
  • 【调试】ftrace(一)基本使用方法
    简介Ftrace是LinuxKernel的官方tracing系统,支持Functiontrace、静态tracepoint、动态Tracepoint的跟踪,还提供各种Tracer,用于统计最大irq延迟、最大函数调用栈大小、调度......
  • 【调试】ftrace(二)新增跟踪点
    内核的各个子系统已经有大量的跟踪点,如果这些跟踪点无法满足工作中的需求,可以自己手动添加跟踪点。添加跟踪点有两种方式,一种是仿照events/目录下的跟踪点,使用TRACE_EVENT......
  • ftrace之function及function_graph使用
    一用途(1)function主要用于跟踪内核函数的调用栈(其被调用过程)(2)function_graph主要用于跟踪内核函数内部调用流程及耗时这两个对内核性能分析的作用不大,主要用来梳理内......
  • 一文学会ftrace的基础用法
    0.官网https://www.kernel.org/doc/html/latest/trace/ftrace.html1.ftrace是什么ftrace是linux原生的一个trace工具,最早在2.6.27引入,跟踪能力强大,可以调试和分析诸如......
  • tracer ftrace笔记(15)—— uprobe——1——Documentation/trace/uprobetracer.rst 翻译
    基于Linux-5.15=========================================Uprobe-tracer:基于Uprobe的事件追踪=========================================:作者:SrikarDronamraju概......
  • tracer ftrace笔记(13)—— kprobe
    基于Linux-5.15一、kprobe简介1.kprobes是为了便于跟踪内核函数执行状态的一种轻量级内核调试技术。可以在内核的绝大多数函数(非inline、非trace自身函数)中动态的......