bpftrace总结

2024/10/31 eBPF bpftrace 共 3345 字,约 10 分钟

不仅要在所有地方hook,还要在那里可编程,eBPF让一切成为现实,而bpftrace让这一过程变的简单。

内置变量 & 函数

  • pid - Process ID (kernel tgid)
  • tid - Thread ID (kernel pid)
  • cgroup - Cgroup ID of the current process
  • uid - User ID
  • gid - Group ID
  • nsecs - Nanosecond timestamp
  • cpu - Processor ID
  • comm - Process name
  • stack - Kernel stack trace
  • ustack - User stack trace
  • arg0, arg1, … etc. - Arguments to the function being traced
  • retval - Return value from function being traced
  • func - Name of the function currently being traced
  • probe - Full name of the probe
  • curtask - Current task_struct as a u64
  • rand - Random number of type u32
  • hist(int n) - Produce a log2 histogram of values of n
  • lhist(int n, int min, int max, int step) - Produce a linear histogram of values of n
  • count() - Count the number of times this function is called
  • sum(int n) - Sum this value
  • min(int n) - Record the minimum value seen
  • max(int n) - Record the maximum value seen
  • avg(int n) - Average this value
  • stats(int n) - Return the count, average, and total for this value
  • delete(@x) - Delete the map element passed in as an argument
  • str(char *s) - Returns the string pointed to by s
  • printf(char *fmt, …) - Print formatted to stdout
  • print(@x[, int top [, int div]]) - Print a map, with optional top entry count and divisor
  • clear(@x) - Delete all key/values from a map
  • sym(void *p) - Resolve kernel address
  • usym(void *p) - Resolve user space address
  • kaddr(char *name) - Resolve kernel symbol name
  • uaddr(char *name) - Resolve user space symbol name
  • reg(char *name) - Returns the value stored in the named register
  • join(char *arr[]) - Prints the string array
  • time(char *fmt) - Print the current time
  • system(char *fmt) - Execute shell command
  • exit() - Quit bpftrace

常用

网络-外发连接

hook: kprobe

查看内核函数参数及返回值。通过tcp_sendmsg 查看tcp外发包情况,tcpsend.bt:

#!/usr/bin/bpftrace

#include <net/sock.h>

k:tcp_sendmsg
{
    @sk[tid] = arg0;
    @size[tid] = arg2;
}
kr:tcp_sendmsg
/@sk[tid]/
{
    $sk = (struct sock *)@sk[tid];
    $size = @size[tid];
    $af = $sk->__sk_common.skc_family;
    if ($af == AF_INET) {
        $daddr = ntop($af, $sk->__sk_common.skc_daddr);
        $saddr = ntop($af, $sk->__sk_common.skc_rcv_saddr);
        $lport = $sk->__sk_common.skc_num;
        $dport = $sk->__sk_common.skc_dport;
        $dport = ($dport >> 8) | (($dport << 8) & 0xff00);
        printf("kr: %-15s %-5d -> %-15s %-5d: %d bytes, retval %d\n",
                $saddr, $lport, $daddr, $dport, $size, retval);
    } else {
        printf("IPv6...\n");
    }
    delete(@sk[tid]);
    delete(@size[tid]);
}

打印tcp IP地址、端口信息:

kr: 192.168.1.2   22    -> 192.168.1.3   62419: 128 bytes, retval 128

用户态-查看用户态函数参数及返回值

类型:kprobe
sum.c:

#include <stdio.h>

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

int main(void)
{
    printf("sum 2 + 3 = %d\n", sum(2, 3));
    printf("sum 3 + 2 = %d\n", sum(3, 2));
    return 0;
}

uprobe, sum.bt:

#!/usr/bin/env bpftrace

uprobe:./sum:"sum"
{
    printf("args: %d + %d\n", arg0, arg1);
}

uretprobe:./sum:"sum"
{
    printf("result: %d\n", reg("ax"));
}

./sum.bt attach uprobe之后,再运行./sum.

Attaching 2 probes...
args: 2 + 3
result: 5
args: 3 + 2
result: 5

用户态审计-bash - history

bash-readline.bt:

#!/usr/bin/env bpftrace

uretprobe:bash:"readline_internal_teardown"
{
    printf(": %s\n", str(reg("ax")));
}

可以抓到shell的所有输入:

Attaching 1 probe...
: whoami
: ps
: cat /etc/passwd >/tmp/log
: cat tmp/log
: cat /tmp/log

获取进程打开文件

bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s\n", comm, str(args->filename)); }'

输出内容很多:

vim /usr/share/vim/vim82/scripts.vim
vim /etc/vim/vimrc.local
vim .
vim /home/ubuntu/.vimrc

阻断(enforce)

override

Kernel 4.16

#!/usr/bin/bpftrace --unsafe

kprobe:__x64_sys_openat
/comm == "vim"/ {
  printf("comm: %s\n", (comm));
  override(-1);
}

vim会被阻断:

vim /tmp/a
vim: error while loading shared libraries: libm.so.6: cannot open shared object file: Operation not permitted

signal

Kernel 5.3

#!/usr/bin/bpftrace --unsafe

kprobe:__x64_sys_execve
/comm == "bash"/ {
  signal(5);
}

attatch的进程会被杀掉:

ls
Trace/breakpoint trap (core dumped)

参考资料

bpftrace-plumbers

文档信息

Search

    Table of Contents