eBPF for Linux Admins: Part VIII
eBPF - This article is part of a series.
In the last chapter, we used kprobes
to trace a kernel function.
But we used that in a kernel module.
In this chapter, we are going to trigger an eBPF program when kernel executes do_sys_openat2
.
For loading modules, there are user space commands (insmod
,rmmod
, modprobe
and modinfo
).
But what we have for loading eBPF program to handle kprobes
?
There are two options;
- Write our own eBPF loader program.
- Use an eBPF utility called
bpftool
Let’s take the second option for now and we will use the other option in a future series 😉
So let’s install the bpftool
first.
sudo apt-get install linux-tools-$(uname -r)
The goal here is same as the previous one ; write an eBPF program that prints the files opened by a process.
- Create a scratch area.
mkdir -p ebpf-tutor/kprobe_example01
cd !$
- Below command is needed for generating arch specific types of running kernel and don’t miss it 😃
bpftool btf dump file /sys/kernel/btf/vmlinux format c >vmlinux.h
- Create the program.
vi ebpf_kprobe_openat.c
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <string.h>
#define TARGET_NAME "sample_write"
SEC("kprobe/do_sys_openat2")
int kprobe__do_sys_openat2(struct pt_regs *ctx) {
char filename[256];
char comm[TASK_COMM_LEN] = {};
const char fmt_str[] = "do_sys_openat2 called by:%s file:%s pid:%d";
u32 pid = bpf_get_current_pid_tgid() ; // Get current process PID
// Read the filename from the second argument
// The x86 arch/ABI have first argument in di and second in si registers (man syscall)
bpf_probe_read(&filename, sizeof(filename), (char *)ctx->si);
// Read the current process name
bpf_get_current_comm(&comm, sizeof(comm));
// Compare process name with our "sample_write" name
if (strcmp(comm, TARGET_NAME) == 0) {
// Print a message with filename, process name, and PID
bpf_trace_printk(fmt_str,sizeof(fmt_str),comm,filename,pid);
return 0;
}
return 0;
}
char _license[] SEC("license") = "GPL";
- Compile it
clang -O2 -g -Wall -target bpf -c ebpf_kprobe_openat.c -o ebpf_kprobe_openat.o
- Load and attach the program to the function. (Somewhat similar to loading module using
insmod
, but not exactly )
sudo bpftool prog load ebpf_kprobe_openat.o /sys/fs/bpf/ebpf_kprobe_openat type kprobe autoattach
- Execute below command on a separate session. (Somewhat similar to
dmesg
, but not exactly 😃 )
sudo cat /sys/kernel/debug/tracing/trace_pipe
- Now execute the
sample_write
file.
The output of the other terminal where we are running cat
will show the details we were looking for.
sample_write-970 [003] ...21 1223.400317: bpf_trace_printk: do_sys_openat2 called by:sample_write file:/etc/ld.so.cache pid:970
sample_write-970 [003] ...21 1223.400578: bpf_trace_printk: do_sys_openat2 called by:sample_write file:/lib/x86_64-linux-gnu/libc.so.6 pid:970
sample_write-970 [003] ...21 1223.401672: bpf_trace_printk: do_sys_openat2 called by:sample_write file:./sample.txt pid:970
You can unload/unregister the eBPF program using below command. (Somewhat similar to rmmod
, but not exactly 😃 😃 )
sudo rm /sys/fs/bpf/ebpf_kprobe_openat
We are getting closer to the wonderful world of eBPF ,but without eBPF maps, we can’t conclude this series. In the next and final chapter, we will discuss eBPF maps and how user space programs can interact with eBPF and vice versa. Stay tuned.!!