工具
bpftool
bpftool安装
依赖包安装
ubuntu 20.04 linux 5.4.169
Copy # apt install pkg-config libelf-dev zlib1g-dev
ubuntu 21.10 linux 5.13.0
Copy # sudo apt install linux-tools-common linux-tools-5.13.0-51-generic linux-cloud-tools-5.13.0-51-generic
Ubuntu 22.04
Copy # sudo apt install pkgconf build-essential libelf-dev linux-tools-common linux-tools-`uname -r` linux-tools-generic
bpftool 安装
Copy # git clone --recurse-submodules https://github.com/libbpf/bpftool.git
# cd bpftool/src
# make && make V=1 install
# bpftool version
bpftool v7.0.0
using libbpf v1.0
features: libbpf_strict
bpftool 常见命令
其他命令
Copy // 查看运行的bpf程序
# bpftool prog list
...
//编号 类型 程序名
51544: sched_cls name handle_policy tag 8c2582bd04b4fb9c gpl
loaded_at 2022-06-23T19:25:49+0800 uid 0
xlated 13936B jited 8157B memlock 16384B map_ids 105,107,96,1214,106,101,102,1213,103
btf_id 5906
...
// 支持的bpf程序类型以及对应的help函数
# bpftool feature
# bpftool feature probe
// 把内核已经加载的 prog 程序固定到文件系统
$ bpftool prog pin name hello /sys/fs/bpf/hi
// 查看link列表
$ bpftool link list
// 生成包含所有bpf程序依赖的内核数据结构header文件vmlinux.h
$
// 查看perf相关的程序
$ bpftool perf show
加载程序到内核
Copy $ bpftool prog load hello.bpf.o /sys/fs/bpf/hello #此命令成功执行没有输出
检查加载到内核的程序
Copy $ bpftool prog list
...
540: xdp name hello tag d35b94b4c0c10efb gpl
loaded_at 2022-08-02T17:39:47+0000 uid 0
xlated 96B jited 148B memlock 4096B map_ids 165,166
btf_id 254
$ bpftool prog show id 540 --pretty
{
"id" : 540, # bpf程序ID,自动生成
"type" : "xdp" , # bpf 程序类型
"name" : "hello" , # bpf 程序名字
"tag" : "d35b94b4c0c10efb" , # 标签,程序的另一个唯一标识
"gpl_compatible" : true , # 使用了 GPL兼容的许可证
"loaded_at" : 1659461987, # 加载时间点的时间戳
"uid" : 0, # 用户ID,0为root
"bytes_xlated" : 96, # 编译为eBPF字节码的大小
"jited" : true , # 是否使用JIT编译
"bytes_jited" : 148, # JIT编译后的大小
"bytes_memlock" : 4096, # 内存预留大小
"map_ids" : [165,166 # 使用的map id
],
"btf_id" : 254 # BTF块ID
}
// 查看程序的命令
$ bpftool prog show id 540
$ bpftool prog show name hello
$ bpftool prog show tag d35b94b4c0c10efb
$ bpftool prog show pinned /sys/fs/bpf/hello
// 查看eBPF字节码内容
$ bpftool prog dump xlated name hello
int hello ( struct xdp_md * ctx ) :
; bpf_printk( "Hello World %d" , counter );
0: (18) r6 = map[id:165][0]+0
2: (61) r3 = * ( u32 * )( r6 +0 )
3: (18) r1 = map[id:166][0]+0
5: (b7) r2 = 15
6: (85) call bpf_trace_printk#-78032
; counter++ ;
7: (61) r1 = * ( u32 * )( r6 +0 )
8: (07) r1 += 1
9: (63) * ( u32 * )( r6 +0 ) = r1
; return XDP_PASS ;
10: (b7) r0 = 2
11: (95) exit
// 查看JIT编译后的机器码
$ bpftool prog dump jited name hello
挂载到内核事件
XDP类型
Copy $ bpftool net attach xdp id 540 dev eth0
$ bpftool net list
xdp:
eth0(2 ) driver id 540
tc:
flow_dissector:
$ ip link show eth0
2: eth0: < BROADCAST,MULTICAST,UP,LOWER_U P > mtu 1500 xdp qdisc
fq_codel state UP
mode DEFAULT group default qlen 1000
...
prog/xdp id 540 tag 9d0e949f89f1a82c jited
查看 trace 输出
Copy // 方法一
$ cat /sys/kernel/debug/tracing/trace_pipe
// 方法二
$ bpftool prog tracelog
如果两种trace输出都没有内容,则需要检查 /sys/kernel/debug/tracing/tracing_on
配置是否开启,1
表示开启 trace。
Map常见操作
Copy $ bpftool map list
165: array name hello.bss flags 0x400
key 4B value 4B max_entries 1 memlock 4096B
btf_id 254
166: array name hello.rodata flags 0x80
key 4B value 15B max_entries 1 memlock 4096B
btf_id 254 frozen
$ bpftool map dump name hello.bss
[{
"value" : {
".bss" : [{
"counter" : 11127
}
]
}
}]
//使用name查看map内容,-p输出十六进制内容
$ sudo bpftool map dump name config -p
[{
"key" : [ "0x00" , "0x00" , "0x00" , "0x00"
],
"value" : [ "0x48" , "0x65" , "0x79" , "0x20" , "0x72" , "0x6f" , "0x6f" , "0x74" , "0x20" , "0x31" , "0x21" , "0x00"
],
"formatted" : {
"key" : 0,
"value" : {
"message" : "Hey root 1!"
}
}
}
]
// 更新map
$ sudo bpftool map update id 407 key 0x00 0x00 0x00 0x00 value 0x48 0x65 0x79 0x20 0x72 0x6f 0x6f 0x74 0x20 0x31 0x21 0x00
卸载程序
Copy $ bpftool net detach xdp dev eth0
$ $ bpftool net list
xdp:
tc:
flow_dissector:
删除内核加载的程序
Copy $ rm /sys/fs/bpf/hello
$ bpftool prog show name hello
eBPF 项目
入门必看,这个项目下有各种场景的ebpf小工具,该项目刚开始都是使用 Python 调用 eBPF 程序实现的工具,后面又用 libbpf 重写了之前的工具。
BCC依赖安装
https://github.com/iovisor/bcc/blob/master/INSTALL.md#ubuntu---source
Copy # For Jammy (22.04)
sudo apt install -y bison build-essential cmake flex git libedit-dev \
libllvm14 llvm-14-dev libclang-14-dev python3 zlib1g-dev libelf-dev libfl-dev python3-distutils
Install and compile BCC
Copy git clone https://github.com/iovisor/bcc.git
mkdir bcc/build; cd bcc/build
cmake ..
make
sudo make install
cmake -DPYTHON_CMD=python3 .. # build python3 binding
pushd src/python/
make
sudo make install
popd
编译libbpf-tools
Copy $ git clone https://github.com/iovisor/bcc.git
$ git submodule update --init --recursive
$ cd libbpf-tools
$ make
常见报错:
1、编译过程出现以下报错:
Copy $ make
...
In file included from javagc.bpf.c:6:
In file included from /home/mars/ebpf-demo/bcc/libbpf-tools/.output/bpf/usdt.bpf.h:6:
/usr/include/linux/errno.h:1:10: fatal error: 'asm/errno.h' file not found
#include <asm/errno.h>
^~~~~~~~~~~~~
1 error generated.
make: *** [Makefile:198: /home/mars/ebpf-demo/bcc/libbpf-tools/.output/javagc.bpf.o] Error 1
解决方式:
Copy $ sudo ln -s /usr/include/asm-generic /usr/include/asm
通过脚本语言写eBPF程序,方便写一些简单的demo程序
安装
ubuntu 20.04 linux 5.4.169
Copy # snap install bpftrace
ubuntu 21.10/22.04
Copy # sudo apt-get install -y bpftrace
bpftrace常见命令
Copy
# 查询所有内核插桩和跟踪点
sudo bpftrace -l
# 使用通配符查询所有的系统调用跟踪点
sudo bpftrace -l 'tracepoint:syscalls:*'
# 使用通配符查询所有名字包含"execve"的跟踪点
sudo bpftrace -l '*execve*'
# 查询execve入口参数格式
$ sudo bpftrace -lv tracepoint:syscalls:sys_enter_execve
tracepoint:syscalls:sys_enter_execve
int __syscall_nr
const char * filename
const char *const * argv
const char *const * envp
# 查询execve返回值格式
$ sudo bpftrace -lv tracepoint:syscalls:sys_exit_execve
tracepoint:syscalls:sys_exit_execve
int __syscall_nr
long ret
使用bpftrace跟踪短时进程
Copy # 使用 bpftrace 来跟踪短时进程
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_execve,tracepoint:syscalls:sys_enter_execveat { printf("%-6d %-8s", pid, comm); join(args->argv);}'
- pid 和 comm 是 bpftrace 内置的变量,分别表示进程 PID 和进程名称(你可以在其官方文档中找到其他的内置变量);
- join(args->argv) 表示把字符串数组格式的参数用空格拼接起来,再打印到终端中。对于跟踪点来说,你可以使用 args->参数名 的方式直接读取参数(比如这里的 args->argv 就是读取系统调用中的 argv 参数)。
# 增加执行时间和父进程id
bpftrace --include linux/sched.h -e 'tracepoint:syscalls:sys_enter_execve,tracepoint:syscalls:sys_enter_execveat { time("%H:%M:%S ");printf("%-6d %-6d %-8s ", pid,curtask->parent->pid, comm); join(args->argv)}'
eCapture
eCapture 是一款基于 eBPF 技术实现的用户态数据捕获工具,其主要功能包括:
不需要 CA 证书,即可捕获 HTTPS/TLS 通信数据的明文。
在 bash 审计场景,可以捕获 bash 命令。
数据库审计场景,可以捕获 mysqld/mariadDB的SQL 查询。
Cilium
Cilium 是一个基于 eBPF 的高性能容器网络方案。其主要功能特性包括:
安全上,支持 L3/L4/L7 安全策略,这些策略按照使用方法又可以分为:
网络上,支持三层平面网络(flat layer 3 network),如:
覆盖网络(Overlay),包括 VXLAN 和 Geneve 等。
Linux 路由网络,包括原生的 Linux 路由和云服务商的高级网络路由等。
eBPF Exporter
eBPF Exporter 是一个将自定义 eBPF 跟踪数据导出到 Prometheus 的工具,它实现了 Prometheus 获取数据的 API,Prometheus 可以通过这些 API 主动拉取到自定义的 eBPF 跟踪数据。
libbpf-bootstrap
Last updated 7 months ago