美文网首页
ebpf学习(1)

ebpf学习(1)

作者: android小奉先 | 来源:发表于2024-08-27 15:06 被阅读0次

本篇介绍

ebpf 是一种观测系统行为的方法, 全称是Extended Berkeley Packet Filter, 本来是观测网络数据包的, 后来由于功能太过强大与方便, 于是越来越多的系统也接入了. 因此目前我们通过ebpf 可以看到非常多的信息. 本系列主要是记录ebpf的一些使用, 等了解使用后, 在慢慢深入机制.

ebpf 的hello world

ebpf 核心部分是内核添加了一个虚拟机, 可以解释bpf指令,而用户态的代码编译成bpf指令后,就可以通过bpf系统调用加载到内核中,由内核的bpf 虚拟机来执行. 而内核的虚拟机可以保证安全,不用担心crash等问题.

接下来我们就先看一段bpf用户态的代码:

#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

#ifdef SEC
#undef SEC
#endif

#define SEC(NAME) __attribute__((section(NAME), used))

SEC("tracepoint/syscalls/sys_enter_execve")

int bpf_prog(void *ctx) {
  char msg[] = "Hello, BPF World";
  bpf_trace_printk(msg, sizeof(msg));
  return 0;
}

char _license[] SEC("license") = "GPL";

这儿的SEC 就是告诉VM 执行该段bpf指令的时机.
使用clang指定target就可以编译bpf

clang -O2 -target bpf -c hello.c -o hello.o

接下来使用bpftool 就可以加载这个目标文件

bpftool prog load hello.o /sys/fs/bpf/hello type raw_tracepoint

load 成功以后,就可以在对应节点上看到:

root@shanks-ThinkPad-T460s:/sys/fs/bpf# ll
-rw------- 1 root root 0  8月 27 21:44 hello
drwx------ 2 root root 0  8月 26 10:38 snap/

利用bpftool 指令也可以看到

root@shanks-ThinkPad-T460s:/sys/fs/bpf# bpftool prog show id 127
127: raw_tracepoint  name bpf_prog  tag a843b44ef43e57e8  gpl
    loaded_at 2024-08-27T21:44:06+0800  uid 0
    xlated 112B  jited 74B  memlock 4096B  map_ids 10

甚至可以dump对应的指令

root@shanks-ThinkPad-T460s:/sys/fs/bpf# bpftool prog dump xlated id 127
   0: (18) r1 = 0x646c726f57204650
   2: (7b) *(u64 *)(r10 -16) = r1
   3: (18) r1 = 0x42202c6f6c6c6548
   5: (7b) *(u64 *)(r10 -24) = r1
   6: (b7) r1 = 0
   7: (73) *(u8 *)(r10 -8) = r1
   8: (bf) r1 = r10
   9: (07) r1 += -24
  10: (b7) r2 = 17
  11: (85) call bpf_trace_printk#-111824
  12: (b7) r0 = 0
  13: (95) exit

可以看到是在打印log, r1 指向的是字符串地址,r2 是字符串长度.

接下来可以查看bpf 日志

root@shanks-ThinkPad-T460s:/sys/kernel/debug/tracing# bpftool prog trace log |more
          docker-981042  [000] ..... 177140.763737: sys_execve(filename: 7fffdae4b580, argv: 3d6003715020, envp: 3d600086d880
)
          docker-981042  [000] ..... 177140.763769: sys_execve(filename: 7fffdae4b580, argv: 3d6003715020, envp: 3d600086d880
)
          docker-981042  [000] ..... 177140.763778: sys_execve(filename: 7fffdae4b580, argv: 3d6003715020, envp: 3d600086d880
)
          docker-981042  [000] ..... 177140.763788: sys_execve(filename: 7fffdae4b580, argv: 3d6003715020, envp: 3d600086d880
)
          docker-981042  [000] ..... 177140.763797: sys_execve(filename: 7fffdae4b580, argv: 3d6003715020, envp: 3d600086d880
)
          docker-981042  [000] ..... 177140.763805: sys_execve(filename: 7fffdae4b580, argv: 3d6003715020, envp: 3d600086d880

可以看到会源源不断在打印log,因为系统在后台也会不停创建新的进程.
刚开始时候设备上没有任何log打印,经过排查,是syscalls对应的tracepoint没打开,需要手动打开,对应的命令如下:

echo 1 > /sys/kernel/tracing/events/syscalls/sys_enter_execve/enable

bpf verifier

运行了上面的例子后,可能会有疑问,是否可以注入一些恶意代码,比如死循环,crash,甚至读取任意内存的逻辑? 如果是这样,那就会给系统的安全性带来致命的危险. 接下来我们看下bpf 是如何避免该问题的.

bpf中有一个安全保护机制verifier,会做如下的校验:

  1. 指令执行一定会结束, 手段是把注入的指令翻译成DAG ,也就是类似与编译器在语法生成树阶段形成的结构, 然后遍历该图,用来保证指令执行一定会结束, 这也使得bpf 中不能包含循环,如果包含了循环,就会被误认为死循环,拒绝加载.
  2. 会分析每个指令,确保访问的内存都是安全的

相关文章

网友评论

      本文标题:ebpf学习(1)

      本文链接:https://www.haomeiwen.com/subject/awmakjtx.html