• bpf对内核的观测


    bpftrace 总的来说是对线上项目的系统调用的函数的观测,因为这时已经不能往函数里面加log了。
    相关的开源项目 https://github.com/iovisor/bpftrace

    1 bpftrace常用命令

    1.1 列出bpftrace 相关命令的list

    bpftrace -l

    $ sudo bpftrace -l | grep accept
    tracepoint:syscalls:sys_enter_accept4
    tracepoint:syscalls:sys_exit_accept4
    tracepoint:syscalls:sys_enter_accept
    tracepoint:syscalls:sys_exit_accept
    kprobe:bpf_lsm_socket_accept
    kprobe:vfs_dentry_acceptable
    kprobe:find_acceptable_alias
    kprobe:security_socket_accept
    kprobe:selinux_socket_accept
    kprobe:apparmor_socket_accept
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    1. 2bpftrace -e 是执行

    使用命令

    # bpftrace -e 'BEGIN { printf("hello n"); }'
    # bpftrace -e 'tracepoint:syscalls:sys_enter_accept { printf("accept\n"); }'
    # bpftrace -e 'tracepoint:syscalls:sys_enter_accept4 { printf("accept4\n"); }'
    # bpftrace -e 'tracepoint:syscalls:sys_enter_connect { printf("connect\n"); }'
    # bpftrace -e 'tracepoint:syscalls:sys_enter_read { printf("read\n"); }'
    # bpftrace -e 'tracepoint:syscalls:sys_enter_write { printf("write\n"); }'
    # bpftrace -e 'tracepoint:syscalls:sys_enter_close { printf("close\n"); }'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    1.3 查看参数 -lv

    $ sudo bpftrace -lv 'tracepoint:syscalls:sys_enter_write'
    tracepoint:syscalls:sys_enter_write
        int __syscall_nr;
        unsigned int fd;
        const char * buf;
        size_t count;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    bpftrace语法结构
    bpftrace的语法结构是参考awk的。
    probes /filter/ { action }
    probes :事件,tracepoint, kprobe, kretprobe, uprobe。两个特殊事件 BEGIN/END,用于脚本开始和结束处执行
    filter :过滤条件,事件触发时,判断条件,例如:/pid == 3245/,表示pid为3245的进程执行。
    action :具体执行的操作,例如:{ printf(“close\n”);} 打印close

    在这里插入图片描述
    想到的应用,如上图中,kprobe的时候记录一下时间t1,kretprobe记录一下时间t2,t2-t1就是这个内核函数调用的时间

    2 bpftrace 可以用到的变量

    内置变量
    bpftrace脚本常用变量如下:
    uid:用户id。
    tid:线程id
    pid:进程id。
    cpu:cpu id。
    cgroup:cgroup id.
    probe:当前的trace点。
    comm:进程名字。
    nsecs:纳秒级别的时间戳。
    kstack:内核栈描述
    curtask:当前进程的task_struct地址。
    args:获取该kprobe或者tracepoint的参数列表
    arg0:获取该kprobe的第一个变量,tracepoint不可用
    arg1:获取该kprobe的第二个变量,tracepoint不可用
    arg2:获取该kprobe的第三个变量,tracepoint不可用
    retval: kretprobe中获取函数返回值
    args->ret: kretprobe中获取函数返回值
    自定义变量
    以’ ′ 标志起来定义与引用变量,例如: '标志起来定义与引用变量,例如: 标志起来定义与引用变量,例如:idx = 0;

    3 高级

    进一步,还有 “自定义变量”,”map变量“,“内置函数”, “文件系统”, “磁盘”, “进程”。

    3.1 内置函数

    (可以查一下,bpftrace的内置函数有哪些)
    应用举例:(具体的路径加程序名:函数名
    #bpftrace -e ‘tracepoint:syscalls:sys_enter_accept4
    { printf(“accept 4 %ld n”, pid); }’

    3.2 文件系统

    统计调用read 的次数,
    #bpftrace e 't:syscalls:sys_enter_read {@[probe]=count();

    3.3 内核内存 栈

    #bpf trace e 't:kmem:kmem_cache_alloc { @bytes[kstack] =
    sum(args -->bytes_alloc);

    分析内核实时函数栈, 统计ip_output 调用栈:
    #bpftrace -e ‘kprobe:ip_output { @[kstack()] = count(); } interval:s:10 { exit(); }’
    #bpftrace -e ‘kprobe:ip_output { @[kstack(3)] = count(); }’

    3.4 Malloc 调用 统计

    #bpftrace e 'u:/lib/x86_64 linux gnu/libc.so.6:malloc
    {@[ustack, comm] = sum(arg0);

    3.5 系统调用 brk 的 统计

    #统计
    统计进程进程发生发生缺页缺页中断中断
    #bpftrace bpftrace --e ‘t:exceptions:page_fault_user { @[ustack, comm] e ‘t:exceptions:page_fault_user { @[ustack, comm] = count(); }’= count(); }’

    3.6 脚本调用

    比如侦测系统调用 accept,查IP,端口…
    inet_csk_accept 这个函数是通过 bpftrace -l grep相关的accept函数,然后结合内核源码找到的
    $ sudo bpftrace -l | grep inet_csk_accept
    kprobe:inet_csk_accept

    eg1 : 新建一个accept.bt的文件,内容如下:(这里需要查阅一下bpftrace的语法,与应用举例了)

    #include 
    
    
    BEGIN
    {
    	printf("%8s %6s %15s", "TIME", "PID", "COMM");
    	printf("%20s %6s %20s %6s\n", "RADDR", "RPORT", "LADDR", "LPORT");	
    }
    
    kretprobe:inet_csk_accept
    {
    	$sk = (struct sock*)retval;  // retval是inet_csk_accept的返回值
    	
    	$raddr = ntop($sk->__sk_common.skc_daddr);  // ntop 是将32位的值转换IP地址加port模式,类似 地址转换函数inet_ntoa、inet_ntop、inet_pton、inet_addr  
    	// ntop([int af, ]int|char[4|16] addr)              Convert IP address data to text
    	$laddr = ntop($sk->__sk_common.skc_rcv_saddr);
    
    	time("%H:%M:%S");
    	printf("%6d %15s", pid, comm);
    	printf("%20s, %20s\n", $raddr, $laddr);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    执行#bpftrace accept.bt
    在这里插入图片描述
    参考:
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    eg2: accept4.bt 里面探测write方法,可以打印出buf,可以包括很多信息,比如用户名,密码,因此这些信息要用密文,至少不那么容易破解。

    tracepoint:syscalls:sys_enter_accept4 
    { 
           printf("accept4 %s\n", comm);
    }
    
    tracepoint:syscalls:sys_enter_accept
    { 
           printf("accept %s\n", comm);
    }
    
    tracepoint:syscalls:sys_enter_connect 
    { 
    	printf(" connect \n");
    }
    
    tracepoint:syscalls:sys_enter_read
    / comm == "nginx"/
    {
    	printf(" read  %s, %d\n", comm, pid);
    }
    
    tracepoint:syscalls:sys_enter_write
    / comm == "git" || comm == "git-remote-http"/
    {
            printf(" write  %s, %d, buf: %s\n", comm, pid, str(args->buf));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    执行 #bpftrace accept4.bt

    4 应用

    类似 tcpdump -i eth0

    5 怎么串联起来呢

    就是要对内核比较熟悉,对文件操作(vfs…),网络操作熟悉,然后灵活运用。
    eg3 : vfs的例子

    #include 
    #include 
    #include 
    
    kprobe:vfs_open 
    / comm == "cat"/ 
    { 
    	printf("vfs_open: %s, name: %s\n", comm, str(((struct path*)arg0)->dentry->d_name.name)); 
    }
    
    
    kprobe:vfs_write
    / comm == "cat"/
    {
    	$file = str(((struct file*)arg0)->f_path.dentry->d_name.name);
    	printf("vfs_write: %s, count: %d, buf:%s\n", $file, arg2, str(arg1));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    可以用cat命令去测试,cat一个文件可以触发vfs_open。参考
    在这里插入图片描述

  • 相关阅读:
    Springboot晋韵戏剧点播网站毕业设计源码112304
    预售, 产品开发完成前没人买,那么之后也不会有
    自动化机械臂喷涂生产线方案五
    【ARM Coresight 系列文章19.2 -- Cortex-A720 AMU 详细介绍】
    python牛客网刷题查漏补缺1
    Django实战项目-学习任务系统-任务完成率统计
    暴力递归到动态规划 03 (背包问题)
    nrf52832 GPIO输入输出设置
    Postman如何做接口自动化测试?
    二氧化钛纳米粒TIO2修饰多肽R8/CTT2/CCK8/GE11/cTAT/CPP/RVG29/SP94(无机纳米粒子偶联多肽)
  • 原文地址:https://blog.csdn.net/qq43645149/article/details/133946248