bpftime
is an unprivileged full-featured eBPF runtime designed to operate in userspace, offering rapid Uprobe and Syscall tracing capabilities. 10x faster than kernel uprobe!
- Unprivileged Userspace eBPF: Seamlessly run eBPF programs in userspace, attaching them to Uprobes and Syscall tracepoints just like in the kernel.
- Performance: Achieve up to 10x speedup compared to kernel uprobe and uretprobe.
- Interprocess eBPF Maps: Utilize userspace eBPF maps in shared userspace memory for summary aggregation or control plane communication.
- Compatibility: Use existing eBPF toolchains like clang and libbpf without any modifications. Compatible with kernel eBPF implementations without requiring privileged access.
- Advanced Tooling: Comes with a cross-platform eBPF interpreter and a high-speed JIT compiler powered by LLVM.
⚠️ Note: This project is actively under development. The API or design might change in upcoming releases, and it's not production ready yet.
With bpftime
, you can build eBPF applications using familiar tools like clang and libbpf, and execute them in userspace. For instance, the malloc
eBPF program traces malloc calls using uprobe and aggregates the counts using a hash map.
To get started:
make build # build the runtime
make -C example/malloc # Build the eBPF program example
LD_PRELOAD=build/runtime/syscall-server/libbpftime-syscall-server.so example/malloc/malloc
In another shell, Run the target program with eBPF inside:
$ LD_PRELOAD=build/runtime/agent/libbpftime-agent.so example/malloc/test
Hello malloc!
malloc called from pid 250215
continue malloc...
malloc called from pid 250215
You can run it again with another process and you can see the output:
12:44:35
pid=247299 malloc calls: 10
pid=247322 malloc calls: 10
Run the target program with eBPF
Alternatively, you can also run the program directly in the kernel eBPF:
$ sudo example/malloc/malloc
15:38:05
pid=30415 malloc calls: 1079
pid=30393 malloc calls: 203
pid=29882 malloc calls: 1076
pid=34809 malloc calls: 8
Left: kernel eBPF | Right: userspace bpftime
The inline hook implementation is based on frida.
see documents/how-it-works.md for details.
We can use the bpftime userspace runtime:
- attach uprobe, uretprobe or all syscall tracepoints(x86 only) eBPF programs to a process or a group of processes
malloc
: count the malloc calls in libc by pidbash_readline
: trace readline calls in bashsslsniff
: trace SSL/TLS raw text in opensslopensnoop
: trace file open or close in a process
- dynamically patch a running process
hot_patch
: demostate how to patch real world CVE in redis or vim.
examples can be found in example dir.
Userspace uprobe and tracepoint compared to kernel:
Probe/Tracepoint Types | Kernel (ns) | Userspace (ns) |
---|---|---|
Uprobe | 4751.462610 | 445.169770 |
Uretprobe | 5899.706820 | 472.972220 |
Syscall Tracepoint | 1499.47708 | 1489.04251 |
LLVM jit benchmark: see github.com/eunomia-bpf/bpf-benchmark for how we evaluate and details.
Across all tests, the LLVM JIT for bpftime consistently showcased superior performance. Both demonstrated high efficiency in integer computations (as seen in log2_int), complex mathematical operations (as observed in prime), and memory operations (evident in memcpy and strcmp). While they lead in performance across the board, each runtime exhibits unique strengths and weaknesses. These insights can be invaluable for users when choosing the most appropriate runtime for their specific use-cases.
Hash map or ring buffer compared to kernel(TODO)
See benchmark dir for detail performance benchmarks.
- some kernel helpers may not be avaliable in userspace
- Cannot directly access kernel data structures or functions like
task_struct
see documents/build-and-test.md for details.
This project is licensed under the MIT License.