ebpf_note
ebpf_note
Ivoripuionebpf入门系列
来源:https://www.ebpf.top/post/bpf_intro_blog/
一些基础知识
ebpf最早在3.18版本中,也就是说3.18以前的无法使用ebpf方案,但是可能可以使用基本已经废弃的支持2.1.75以后版本的cbpf。
ebpf架构图:
也就是说,内核可以hook的程序类型有:
- kprobes:内核函数动态追踪
- uprobes:用户态函数动态追踪
- tracepoints:内核中的静态追踪(估计用不到正常)
- perf_events:定时采样和 PMC(需要注释一下)
BCC helloworld
1 | #!/usr/bin/python3 |
每次调用内核函数execve就会打印:“Hello, World!”,同时因为是debug模式所以会同时打印进程名称等信息。
在BPF程序中按照PID过滤进程
Linux系统中进程/线程在内核空间以结构体task_struct
进行进程/线程维度的资源隔离。创建方式上Linux线程通过clone
函数实现,进程/线程底层都是do_fork
函数创建。
POSIX Thread是以一个定义Thread相关函数的API集,NPTL是对这个API集的实现,举个例子,可以使用用户态函数pthread_create()
创建一个线程,此时内核就创建了一个task_struct
结构体。
用户态和内核态线程的区别:
- 用户态:负责执行线程的创建、销毁等操作;
- 内核态:作为调度单元;
进程中第一个创建的线程称作主线程作为线程组的Leader,线程组的id使用tgid标识,主线程的pid与tgid相同。
也就是说,用户态的pid其实就是线程组里主线程的tgid,那么要在BPF中获取pid,获取当前线程组里任意线程task_struct
结构体的tgid就行了。
bpf_get_current_pid_tgid
的返回值为current->tgid << 32 | current->pid
:
current->tgid | current->pid |
---|---|
用户态pid(占据32位) | 用户态tid(占据32位) |
因此要获取用户态pid,我们只需要获得bpf_get_current_pid_tgid
返回值的高32位即可,即
1 | u32 pid = bpf_get_current_pid_tgid()>>32; |
若要获取tid
,则是:
1 | u32 pid = bpf_get_current_pid_tgid(); |
举个BCC的例子获取所有执行execve
函数用户态pid则是:
1 | #!/usr/bin/python3 |