Skip to content

Commit

Permalink
add bpftime documents
Browse files Browse the repository at this point in the history
  • Loading branch information
yunwei37 committed Jan 13, 2024
1 parent 969fe9a commit 7b8e393
Show file tree
Hide file tree
Showing 11 changed files with 598 additions and 3 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@ eunomia-bpf
GPTtrace
docs/setup
docs/tutorials
docs/bpftime
.cache
58 changes: 58 additions & 0 deletions docs/bpftime/documents/avaliable-features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# available kernel features in userspace

## avalibale map types

Userspace eBPF shared memory map types:

- BPF_MAP_TYPE_HASH
- BPF_MAP_TYPE_ARRAY
- BPF_MAP_TYPE_RINGBUF
- BPF_MAP_TYPE_PERF_EVENT_ARRAY
- BPF_MAP_TYPE_PERCPU_ARRAY
- BPF_MAP_TYPE_PERCPU_HASH

User-kernel shared maps:

- BPF_MAP_TYPE_HASH
- BPF_MAP_TYPE_ARRAY
- BPF_MAP_TYPE_PERCPU_ARRAY
- BPF_MAP_TYPE_PERF_EVENT_ARRAY

## avaliable program types

Compatible with kernel eBPF program types:

- tracepoint:raw_syscalls:sys_enter
- tracepoint:syscalls:sys_exit_*
- tracepoint:syscalls:sys_enter_*
- uretprobe:*
- uprobe:*

## available helpers

### maps

- `bpf_map_lookup_elem`: Helper function for looking up an element in a BPF map.
- `bpf_map_update_elem`: Helper function for updating an element in a BPF map.
- `bpf_map_delete_elem`: Helper function for deleting an element from a BPF map.

### kernel_helper_group

- `bpf_probe_read`: Helper function for reading data from a kernel address.
- `bpf_ktime_get_ns`: Helper function for getting the current time in nanoseconds.
- `bpf_trace_printk`: Helper function for printing debug messages from eBPF programs.
- `bpf_get_current_pid_tgid`: Helper function for getting the current PID and TGID (Thread Group ID).
- `bpf_get_current_uid_gid`: Helper function for getting the current UID (User ID) and GID (Group ID).
- `bpf_get_current_comm`: Helper function for getting the current process's name.
- `bpf_strncmp`: Helper function for comparing two strings.
- `bpf_get_func_arg`: Helper function for getting the value of a function argument.
- `bpf_get_func_ret`: Helper function for getting the value of a function return ID.
- `bpf_get_retval`: Helper function for getting the return value of a function.
- `bpf_set_retval`: Helper function for setting the return value of a function.
- `bpf_probe_read_str`: Helper function for reading a null-terminated string from a user address.
- `bpf_get_stack`: Helper function for retrieving the current kernel stack.

## Others

- Support kernel or userspace verifier
- Test JIT with bpf_conformance
Binary file added docs/bpftime/documents/bpftime-kernel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
103 changes: 103 additions & 0 deletions docs/bpftime/documents/bpftime.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Bpftime: A High-Performance User-Space eBPF Runtime

Yusheng Zheng, Tong Yu

Today, we are thrilled to introduce Bpftime, a Open-sourced full-featured, high-performance eBPF runtime, designed to operate in user space. It supports eBPF kernel features like uprobe, syscall trace, can be attached to other process, having a shared interprocess map, with LLVM jit, a handcrafted x86 jit. It also can be used with existing eBPF toolchains like libbpf and clang without any changed.

It can speed up eBPF programs by 10x compared to kernel uprobes, and can be used in embedded systems, IoT, edge computing, smart contracts, and cloud-native solutions.

The github repo is: <https://github.com/eunomia-bpf/bpftime>

## Bpftime vs. Alternatives

### WebAssembly (Wasm) in User Space

While Wasm has its advantages, it also comes with limitations:

- High performance costs due to security concerns with external APIs like Wasi, which require additional validation and runtime checks, often necessitating extra memory copies.
- Manual integration needed, with embedding in compile times instead of dynamic uprobe/kprobe.
- Less adaptable to API version changes due to lack of BTF CO-RE support.
- Reliance on underlying libraries for complex operations.

### eBPF in Kernel Space

The kernel space eBPF also presents its own set of challenges:

- Kernel UProbe implementation necessitates two kernel context switches, resulting in significant performance overhead.
- Limited features and unsuitability for plugin or other use cases.
- Running eBPF programs in kernel mode requires root access, increasing the attack surface and posing risks like container escape.
- Inherent vulnerabilities in eBPF can lead to Kernel Exploits.

### Other User-Space eBPF Runtimes

There are other user-space eBPF runtimes available, such as Ubpf and Rbpf:

- Ubpf: Ubpf offers ELF parsing, a simple hash map, and JIT for arm64 and x86.
- Rbpf: Rbpf provides a helper mechanism, x86 JIT, and a VM.

However, it has several limitations:

- Complex integration and usage.
- Inability to use kernel eBPF libraries and toolchains like libbpf, bpftrace, or clang.
- Lack of attach support.
- Absence of interprocess maps.
- Limited functionality in user space.
- JIT support only for arm64 or x86.

Despite these limitations, existing user-space eBPF runtimes have been used in several innovative projects, including:

- **Qemu+uBPF**: This project combines Qemu, an open-source machine emulator and virtualizer, with uBPF to enhance its capabilities. You can check out a demonstration in this [video](https://www.youtube.com).
- **Oko**: Oko extends Open vSwitch-DPDK with BPF, enhancing tools for better integration. More details are available on its [GitHub](https://github.com/oko) page.
- **Solana**: Solana uses user-space eBPF for high-performance smart contracts. You can explore more on its [GitHub](https://github.com/solana-labs/solana) page.
- **DPDK eBPF**: DPDK eBPF provides libraries for fast packet processing, further enhanced by user-space eBPF.
- **eBPF for Windows**: This project brings eBPF toolchains and runtime to the Windows kernel, expanding the reach of eBPF.

Additionally, user-space eBPF runtimes have been discussed in academic papers like "Rapidpatch: Firmware Hotpatching for Real-Time Embedded Devices" and "Femto-Containers: Lightweight Virtualization and Fault Isolation For Small Software Functions on Low-Power IoT Microcontrollers".

These projects demonstrate the versatility and potential of user-space eBPF runtimes in diverse areas such as network plugins, edge runtime, smart contracts, hotpatching, and even Windows support. The future of eBPF is indeed promising!

## Why Bpftime?

Bpftime addresses these limitations and offers a host of powerful features:

- Runs eBPF in user space just like in the kernel, achieving a 10x speedup vs. kernel uprobes.
- Uses shared eBPF maps for data & control.
- Compatible with clang, libbpf, and existing eBPF toolchains; supports CO-RE & BTF.
- Supports `external functions`(ffi) and pointers like kfunc.
- Includes a cross-platform interpreter, fast LLVM JIT compiler, and a handcrafted x86 JIT in C for limited resources.
- Can inject eBPF runtime into any running process without the need for a restart or manual recompilation.
- Runs not only in Linux but also in all Unix systems, Windows, and even IoT devices.

## benchmark

How is the performance of `userspace uprobe` compared to `kernel uprobes`? Let's take a look at the following benchmark results:

TODO: results

It can be attached to functions in running process just like the kernel uprobe does.

How is the performance of LLVM JIT/AOT compared to other eBPF userspace runtimes, native code or wasm runtimes? Let's take a look at the following benchmark results:

You can find detail benchmark results in [https://github.com/eunomia-bpf/bpf-benchmark](https://github.com/eunomia-bpf/bpf-benchmark)

## AI for eBPF Code Generation

Bpftime is also exploring the use of AI for eBPF code generation. GPT4, with the help of AI agents, can generate eBPF code with up to 80% accuracy. More information about this can be found on:

- [NL2eBPF online website](https://gpt-2-bpftrace.vercel.app/)
- [GPTtrace](https://github.com/eunomia-bpf/GPTtrace).

## The Future of Bpftime

The Bpftime project is continuously evolving, with more features in the pipeline:

- An AOT compiler for eBPF can be easily added based on the LLVM IR.
- More map types and distribution maps support.
- User-space eBPF to speed up fuse.
- eBPF for GPU sharing programs.
- RDMA with distribution eBPF runtimes.
- User-space eBPF syscall bypass.

Bpftime is an open-source project and can be found on [GitHub](https://github.com/eunomia-bpf/bpftime).

In conclusion, Bpftime is set to revolutionize the tech sphere with its high performance, compatibility with existing eBPF toolchains, and potential for AI-enhanced code generation. Stay tuned for more developments from this promising project!
Binary file added docs/bpftime/documents/bpftime.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 61 additions & 0 deletions docs/bpftime/documents/build-and-test.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Building and run bpftime

## Install Dependencies

Install the required packages:

```bash
sudo apt install -y --no-install-recommends \
libelf1 libelf-dev zlib1g-dev make git libboost1.74-all-dev \
binutils-dev libyaml-cpp-dev llvm
git submodule update --init --recursive
```

We've tested on Ubuntu 23.04. The recommended `gcc` >= 12.0.0 `clang` >= 16.0.0

On Ubuntu 20.04, you may need to manually switch to gcc-12.

### Build and install cli tool

```bash
sudo apt-get install libelf-dev zlib1g-dev # Install dependencies
make release && make install # Build and install the runtime
export PATH=$PATH:~/.bpftime
```

Then you can run cli:

```console
$ bpftime
Usage: bpftime [OPTIONS] <COMMAND>
...
```

## Compilation for vm

Build the complete runtime:

```bash
make build
```

On old systems, you may need to buil with old binutils version(TODO: fix it):

```bash
make build-old-binutils
```

For a lightweight build without the runtime (only vm library and LLVM JIT):

```bash
make build-vm # build the simple vm with a simple jit
make build-llvm # build the vm with llvm jit
```

## Testing

Run the test suite for runtime to validate the implementation:

```bash
make unit-test
```
10 changes: 10 additions & 0 deletions docs/bpftime/documents/how-it-works.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# the design and implementation of bpftime

The hook implementation is based on binary rewriting and the underly technique is inspired by:

- Userspace function hook: [frida-gum](https://github.com/frida/frida-gum)
- Syscall hooks: [zpoline: a system call hook mechanism based on binary rewriting](https://www.usenix.org/conference/atc23/presentation/yasukata)

![How it works](bpftime.png)

TODO
122 changes: 122 additions & 0 deletions docs/bpftime/documents/usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Usgae

It's at a very early stage and may contain bugs on more platforms and eBPF programs.

## Run with JIT enabled

Set `BPFTIME_USE_JIT=true` in the server to enable JIT, for example, when running the server:

```sh
LD_PRELOAD=~/.bpftime/libbpftime-syscall-server.so BPFTIME_USE_JIT=true example/malloc/malloc
```

## Uprobe and uretprobe

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.

You can refer to [documents/build-and-test.md](build-and-test.md) for how to build the project.

To get started, you can build and run a libbpf based eBPF program starts with `bpftime` cli:

```console
make -C example/malloc # Build the eBPF program example
bpftime load ./example/malloc/malloc
```

In another shell, Run the target program with eBPF inside:

```console
$ bpftime start ./example/malloc/test
Hello malloc!
malloc called from pid 250215
continue malloc...
malloc called from pid 250215
```

You can also dynamically attach the eBPF program with a running process:

```console
$ ./example/malloc/test & echo $! # The pid is 101771
[1] 101771
101771
continue malloc...
continue malloc...
```

And attach to it:

```console
$ sudo bpftime attach 101771 # You may need to run make install in root
Inject: "/root/.bpftime/libbpftime-agent.so"
Successfully injected. ID: 1
```

You can see the output from original program:

```console
$ bpftime load ./example/malloc/malloc
...
12:44:35
pid=247299 malloc calls: 10
pid=247322 malloc calls: 10
```

Alternatively, you can also run our sample eBPF program directly in the kernel eBPF, to see the similar output:

```console
$ 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
```

## Syscall tracing

An example can be found at [benchmark/hash_maps](../benchmark/hash_maps/).

Build the example:

```sh
make -C benchmark/hash_maps
```

Start server:

```sh
$ sudo ~/.bpftime/bpftime load benchmark/hash_maps/opensnoop
[2023-10-01 16:46:43.409] [info] manager constructed
[2023-10-01 16:46:43.409] [info] global_shm_open_type 0 for bpftime_maps_shm
[2023-10-01 16:46:43.410] [info] Closing 3
[2023-10-01 16:46:43.411] [info] mmap64 0
[2023-10-01 16:46:43.411] [info] Calling mocked mmap64
[2023-10-01 16:46:43.411] [info] Closing 3
[2023-10-01 16:46:43.411] [info] Closing 3
[2023-10-01 16:46:43.423] [info] Closing 3
[2023-10-01 16:46:43.423] [info] Closing 3
```

Start victim:

```console
$ sudo ~/.bpftime/bpftime start -s benchmark/hash_maps/victim
[2023-10-01 16:46:58.855] [info] Entering new main..
[2023-10-01 16:46:58.855] [info] Using agent /root/.bpftime/libbpftime-agent.so
[2023-10-01 16:46:58.856] [info] Page zero setted up..
[2023-10-01 16:46:58.856] [info] Rewriting segment from 559a839b4000 to 559a839b5000
[2023-10-01 16:46:58.859] [info] Rewriting segment from 7f130aa22000 to 7f130ab9a000
[2023-10-01 16:46:59.749] [info] Rewriting segment from 7f130acc3000 to 7f130adb0000
[2023-10-01 16:47:00.342] [info] Rewriting segment from 7f130ae9c000 to 7f130afcd000
[2023-10-01 16:47:01.072] [info] Rewriting segment from 7f130b125000 to 7f130b1a3000
.....
[2023-10-01 16:47:02.084] [info] Attach successfully
[2023-10-01 16:47:02.084] [info] Transformer exiting..

Opening test.txt..
VICTIM: get fd 3
VICTIM: closing fd
Opening test.txt..
VICTIM: get fd 3
VICTIM: closing f
```
Binary file not shown.
Loading

0 comments on commit 7b8e393

Please sign in to comment.