Tuesday, July 4, 2023

eBPF Programming Setup

Extended Berkeley Packet Filter [eBPF] is a technology that runs sandboxed programs in privileged context like the OS kernel to safely and efficiently extend the capabilities of the kernel at runtime without requiring changes to the kernel source code. libbpf is a C-based library that takes compiled BPF object files and loads and verifies them into the kernel attachiing BPF programs to various kernel hooks and execute custom code.

Let's check it out!

Software
Follow all instructions from the previous post to install CLion and VS Code on Ubuntu Linux. Also install the bpftool which was added to the 2017 Linux kernel as a user space utility to introspect the eBPF subsystem.
 git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
 cd linux
 cd tools/bpf/bpftool
 make
 sudo make install
 bpftool version


Alternatively, download bpftool binary from the Github releases and extract into /usr/local/bin directory.

Hello World
Create your first BPF program using this simple eBPF CO-RE application as a reference however using CLion. Launch CLion | New Project | C Executable | Location: /home/stevepro/HelloWorld | Language std: C11

Create

A new C project will be created which automatically adds the following two files: main.c and CMakeLists.txt
 main.c  CMakeLists.txt
 #include <stdio.h>
 int main()
 {
   printf( "Hello, World!\n" );
   return 0;
 }
 cmake_minimum_required(VERSION 3.19)
 project(HelloWorld C)
 
 set(CMAKE_C_STANDARD 11)
 
 add_executable(HelloWorld main.c)

In the Terminal window within CLion IDE enter the following commands to install and buld the libbpf library:
 git clone https://github.com/libbpf/libbpf
 cd libbpf/src
 make
 sudo make install
 cd ../..

Next, enter commands to create the vmlinux.h file. Create and build the Hello BPF program + skeleton file:
 bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
 touch hello.bpf.c
 clang -g -O2 -target bpf -D__TARGET_ARCH_x86_64 -I libbpf/src -c hello.bpf.c -o hello.bpf.o
 bpftool gen skeleton hello.bpf.o > hello.skel.h

 hello.bpf.c  CMakeLists.txt
 #include "vmlinux.h"
 #include "bpf_helpers.h"
 
 SEC("tracepoint/syscalls/sys_enter_execve")
 int hello_bpf(struct trace_event_raw_sys_enter *ctx)
 {
   bpf_printk("Hello world!\n");
   return 0;
 }
 char LICENSE[] SEC("license") = "GPL";
 cmake_minimum_required(VERSION 3.19)
 project(HelloWorld C)
 
 set(CMAKE_C_STANDARD 11)
 
 include_directories(.)
 link_directories(libbpf libbpf/src)
 
 add_executable(HelloWorld main.c)
 target_link_libraries(HelloWorld bpf elf z)

Rename main.c to hello.c and update the driver program code. Edit configurations | Run with root privileges

Set break point in hello.c | HelloWorld | Debug or Press F5 to launch your first Hello World BPF program!

IMPORTANT you can tail BPF output in Terminal window: sudo cat /sys/kernel/debug/tracing/trace_pipe

Hello Maps
BPF maps are generic structures for storing different types of data accessible between kernel + user space. Launch CLion | New Project | C Executable | Location: /home/stevepro/HelloMaps | Language std: C11

Create

Repeat the process similar to Hello World: Install the libbpf library. Create the vmlinux header file, the Maps BPF program and driver code. Compile code. Update the CMakeLists build script and Run with root privileges:


libbpf-bootstrap
libbpf-bootstrap provides a starting point for building your own BPF applications with things like BPF Compile Once-Run Everywhere [CO-RE] and vmlinux.h. Numerous more BPF samples can be found at the Linux repo.
 CUSTOM: minimal  SOURCE: minimal
 CUSTOM: minimal_ns  SOURCE: minimal_ns
 CUSTOM: minimal_legacy  SOURCE: minimal_legacy
 CUSTOM: bootstrap  SOURCE: bootstrap
 CUSTOM: uprobe  SOURCE: uprobe
 CUSTOM: usdt  SOURCE: usdt
 
 CUSTOM: fentry  SOURCE: fentry
 CUSTOM: kprobe  SOURCE: kprobe
 CUSTOM: ksyscall  SOURCE: ksyscall
 CUSTOM: tc  SOURCE: tc
 CUSTOM: profile  SOURCE: profile
 CUSTOM: sockfilter  SOURCE: sockfilter

Summary
Although libbpf allows BPF programs to be loaded, verified and attached to various kernel hooks and execute custom code there is currently no way to debug BPF programs' source code interactively. Therefore, this now presents alternatives to explore unit testing and mock BPF programs. This will be the topic of the next post.