BumbleBee 体验

个人兴趣,用ebpf技术可直接hack 进入系统态执行,BumbleBee作为类似nodejs/Jenkins一样的脚手架与部署工具,可以很方便的开发eBPF程序并完成部署

环境

win11 + ubuntu-1804-wls2

wsl: 5.10.102.1 (从5.10.74.3开始不用手动编译wsl2内核了)

docker

1
2
# wsl内核升级
wsl --update

下载并安装BumbleBee工具

1
curl -sL https://run.solo.io/bee/install | sh

添加到环境变量

1
export PATH=$HOME/.bumblebee/bin:$PATH

创建工程模板

1
bee init

会让用户选择 5 个配置

1
2
3
4
5
6
7
8
Selected Language: C # 样版代码使用的开发语言,目前仅支持C、Rust
Selected Program Type: Network # 程序类型:网络 、文件系统,生成的模板分别对应于 tcp_connet 和 open 函数
Selected Map Type: HashMap # 选择 map 类型
Selected Output Type: print # map 数据的展现方式,日志打印、计数或者指标导出
Selected Output Type: BPF Program File Location probe.c # 步骤 5 eBPF 程序保存文件名

# 最终提示
SUCCESS Successfully wrote skeleton BPF program

生成的样板程序

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include "vmlinux.h"
#include "bpf/bpf_helpers.h"
#include "bpf/bpf_core_read.h"
#include "bpf/bpf_tracing.h"
#include "solo_types.h"

// 1. Change the license if necessary
char __license[] SEC("license") = "Dual MIT/GPL";

struct dimensions_t {
// 2. Add dimensions to your value. This struct will be used as the key in the hash map of your data.
// These will be treated as labels on your metrics.
// In this example we will have single field which contains the PID of the process
u32 pid;
} __attribute__((packed));

// This is the definition for the global map which both our
// bpf program and user space program can access.
// More info and map types can be found here: https://www.man7.org/linux/man-pages/man2/bpf.2.html
struct {
__uint(max_entries, 1 << 24);
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, struct dimensions_t);
__type(value, u64);
} values SEC(".maps.print");

SEC("kprobe/tcp_v4_connect")
int BPF_KPROBE(tcp_v4_connect, struct sock *sk)
{
// initialize our struct which will be the key in the hash map
struct dimensions_t key;
// initialize variable used to track PID of process calling tcp_v4_connect
u32 pid;
// define variable used to track the count of function calls, and a pointer to it for plumbing
u64 counter;
u64 *counterp;

// get the pid for the current process which has entered the tcp_v4_connect function
pid = bpf_get_current_pid_tgid();
key.pid = pid;

// check if we have an existing value for this key
counterp = bpf_map_lookup_elem(&values, &key);
if (!counterp) {
// debug log to help see how the program works
bpf_printk("no entry found for pid: %u}", key.pid);
// no entry found, so this is the first occurrence, set value to 1
counter = 1;
}
else {
bpf_printk("found existing value '%llu' for pid: %u", *counterp, key.pid);
// we found an entry, so let's increment the existing value for this PID
counter = *counterp + 1;
}
// update our map with the new value of the counter
bpf_map_update_elem(&values, &key, &counter, 0);


return 0;
}

编译成实际eBPF程序

会将C程序编译成eBPF程序产品(probe.o)并做成docker镜像

1
bee build probe.c my_probe:v1

image

运行编译好的eBPF程序

1
bee run my_probe:v1

image

发布eBPF程序

1
2
3
bee tag my_probe:v1 dwh0403/my_probe:v1
bee login
bee push dwh0403/my_probe:v1