Skip to content

Commit

Permalink
Add support for ebpf-verifier (#14)
Browse files Browse the repository at this point in the history
* Initial ebpf-verifier

* Fix building without ebpf-verifier

* Initial update for new bpftime-verifier

* Update changes

* Fix runtime cmakelists

* Add simple tests

* stage changes

* Update

* Update tests

* Update

* Update tests

* Update

* Add workflow to test bpftime-verifier

* Fix CI

* Update CI

* Update CMakeLists

* Fix Ci

* Update CI

* Fix CI

* Fix CI

* Fix CI

* Fix CI

* Fix CI

* Update
  • Loading branch information
Officeyutong authored Oct 3, 2023
1 parent 876db6c commit e7f7717
Show file tree
Hide file tree
Showing 31 changed files with 977 additions and 86 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/runtime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
run: |
sudo apt install -y --no-install-recommends \
libelf1 libelf-dev zlib1g-dev make git libboost-dev \
libboost-program-options-dev binutils-dev
libboost-program-options-dev binutils-dev libyaml-cpp-dev
- name: build runtime
run: make build-old-binutils
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/test-cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: Test whether CLI works properly

on:
push:
branches: [master]
branches: ["*"]
pull_request:
branches: [master]
branches: ["*"]

jobs:
build-runtime-cli-and-test-cli:
Expand All @@ -15,14 +15,15 @@ jobs:
submodules: 'recursive'
- name: Install dependencies
run: |
sudo apt-get install binutils-dev libboost1.74-all-dev libelf-dev zlib1g-dev
sudo apt-get install binutils-dev libboost1.74-all-dev libelf-dev zlib1g-dev libyaml-cpp-dev gcc-12 g++-12
- name: Build and install runtime
run: |
make install
CC=gcc-12 CXX=g++-12 make install
- name: Build and install CLI
run: |
cd tools/cli-rs
RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --target x86_64-unknown-linux-gnu
mkdir -p ~/.bpftime
cp ./target/x86_64-unknown-linux-gnu/release/bpftime ~/.bpftime
- uses: actions/upload-artifact@v3
with:
Expand Down
26 changes: 26 additions & 0 deletions .github/workflows/test-verifier.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Test whether bpftime-verifier works properly

on:
push:
branches: ["*"]
pull_request:
branches: ["*"]

jobs:
build-and-run-verifier-test-target:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: Install dependencies
run: |
sudo apt-get update -y
sudo apt-get install binutils-dev libboost1.74-all-dev libelf-dev zlib1g-dev ninja-build libyaml-cpp-dev -y
- name: Build test target
run: |
cmake -DBPFTIME_ENABLE_UNIT_TESTING=YES -DBPFTIME_LLVM_JIT=NO -DUSE_NEW_BINUTILS=YES -DENABLE_EBPF_VERIFIER=YES -DCMAKE_BUILD_TYPE:STRING=Release -S . -B build -G Ninja
cmake --build build --config Release --target bpftime_verifier_tests
- name: Run tests
run: |
./build/bpftime-verifier/bpftime_verifier_tests
6 changes: 3 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
[submodule "third_party/bpftool"]
path = third_party/bpftool
url = https://github.com/libbpf/bpftool
[submodule "third_party/ebpf-verifier"]
path = third_party/ebpf-verifier
url = https://github.com/vbpf/ebpf-verifier
[submodule "third_party/spdlog"]
path = third_party/spdlog
url = https://github.com/gabime/spdlog
[submodule "verifier/ebpf-verifier"]
path = bpftime-verifier/ebpf-verifier
url = https://github.com/vbpf/ebpf-verifier
8 changes: 4 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,13 @@ function(add_ebpf_program_target target_name source_file output_file)
add_dependencies(${target_name} copy_headers)
endfunction()

# ebpf-verifier
option(ENABLE_EBPF_VERIFIER "Whether to enable ebpf verifier" OFF)
set(CMAKE_POSITION_INDEPENDENT_CODE YES)

# ebpf-verifier
option(ENABLE_EBPF_VERIFIER "Whether to enable ebpf verifier" YES)

if(${ENABLE_EBPF_VERIFIER})
add_subdirectory(third_party/ebpf-verifier)
set(EBPF_VERIFIER_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/ebpf-verifier/src)
add_subdirectory(bpftime-verifier)
endif()

# spdlog
Expand Down
3 changes: 1 addition & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ build-old-binutils: ## build the package with old binutils


release: ## build the package
(cmake -Bbuild -DBPFTIME_ENABLE_UNIT_TESTING=0 && cmake --build build --config Release -j) || (cmake -Bbuild -DBPFTIME_ENABLE_UNIT_TESTING=0 -DUSE_NEW_BINUTILS=YES && cmake --build build --config Release -j)
(cmake -Bbuild -DBPFTIME_ENABLE_UNIT_TESTING=0 && cmake --build build --config Release -j --target install) || (cmake -Bbuild -DBPFTIME_ENABLE_UNIT_TESTING=0 -DUSE_NEW_BINUTILS=YES && cmake --build build --config Release -j --target install)

build-vm: ## build only the core library
make -C vm build
Expand All @@ -60,4 +60,3 @@ clean: ## clean the project
make -C runtime clean
make -C vm clean
install: release ## Invoke cmake to install..
cmake --build build --config Release --target install
1 change: 1 addition & 0 deletions bpftime-verifier/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dump*
38 changes: 38 additions & 0 deletions bpftime-verifier/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
add_library(bpftime-verifier STATIC src/bpftime-verifier.cpp src/platform-impl.cpp)
add_subdirectory(ebpf-verifier)

set_property(TARGET bpftime-verifier PROPERTY CXX_STANDARD 20)

target_include_directories(bpftime-verifier
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/ebpf-verifier/src
${CMAKE_CURRENT_SOURCE_DIR}/include
${LIBBPF_INCLUDE_DIRS}
)

target_link_libraries(bpftime-verifier PUBLIC ebpfverifier ${LIBBPF_LIBRARIES} z elf)

add_dependencies(bpftime-verifier ebpfverifier libbpf)

set(BPFTIME_VERIFIER_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/include)

set(TEST_SOURCES
test/simple.cpp
test/map.cpp
test/non_kernel_helper.cpp
)

Include(FetchContent)

FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v3.0.1
)

FetchContent_MakeAvailable(Catch2)

add_executable(bpftime_verifier_tests ${TEST_SOURCES})
add_dependencies(bpftime_verifier_tests bpftime-verifier)
target_link_libraries(bpftime_verifier_tests PRIVATE bpftime-verifier Catch2::Catch2WithMain)
target_include_directories(bpftime_verifier_tests PRIVATE ${BPFTIME_VERIFIER_INCLUDE})
add_test(NAME bpftime_verifier_tests COMMAND bpftime_verifier_tests)
76 changes: 76 additions & 0 deletions bpftime-verifier/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# bpftime-verifier

A simple wrapper around ebpf-verifier, providing more simple user interfaces.

## Usage

### Setup cmake
```
add_subdirectory(bpftime-verifier)
add_dependencies(MY_TARGET bpftime-verifier)
target_link_libraries(MY_TARGET bpftime-verifier)
target_include_directories(MY_TARGET PUBLIC ${BPFTIME_VERIFIER_INCLUDES}s)
```
### Invokes the verifier

```cpp
#include <bpftime-verifier.hpp>
#include <map>
#include <iostream>
#include <optional>
#include <string>
using namespace bpftime;

int main(){
// Set maps that the current ebpf program will use
set_map_descriptors(std::map<int, BpftimeMapDescriptor>{
{ 2333, BpftimeMapDescriptor{ .original_fd = 233,
.type = BPF_MAP_TYPE_HASH,
.key_size = 8,
.value_size = 4,
.max_entries = 8192,
.inner_map_fd = 0 } } });

// Set helpers that the current ebpf program will use
// This can include both kernel-provided helpers and self-defined helpers
set_available_helpers(std::vector<int32_t>{ 1, 1000001 });
// For user-defined helpers, prototype should also be defined
set_non_kernel_helpers(std::map<int, BpftimeHelperProrotype>{
{1000001, BpftimeHelperProrotype{
.name = "my_helper",
.return_type = EBPF_RETURN_TYPE_INTEGER,
.argument_type = {
EBPF_ARGUMENT_TYPE_ANYTHING, // This indicates an arbiraty 64bit integer
EBPF_ARGUMENT_TYPE_PTR_TO_MAP, // This indicates a pointer of map
}
}}
});

const uint64_t prog_with_map_1[] = {
0x00000002000001b7,
0x00000000fff81a7b,
0x000000000000a2bf,
0xfffffff800000207,
0x0000091d00001118,
0x0000000000000000,
0x0000000100000085,
0x0000000000000061,
0x0000000000000095 };

// Do the verification
std::optional<std::string> result = auto ret =
verify_ebpf_program(prog_with_map_1, std::size(prog_with_map_1),
"uprobe//proc/self/exe:uprobed_sub");

// If verification succeeded, verify_ebpf_program will return an empty optional. Otherwise, failure message will be returned
if(result.has_value()){
std::cerr << result.value();
} else {
std::cout << "Done!";
}
}
```

## Important notes
Things set by `set_available_helpers`, `set_non_kernel_helpers` and `set_map_descriptors` are thread-local, meaning that each thread has its own instance of things set by these functions. So you need to set the corresponding values in each thread you use.
1 change: 1 addition & 0 deletions bpftime-verifier/ebpf-verifier
Submodule ebpf-verifier added at fd85b8
72 changes: 72 additions & 0 deletions bpftime-verifier/include/bpftime-verifier.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#ifndef _BPFTIME_VERIFIER_HPP
#define _BPFTIME_VERIFIER_HPP
#include <cinttypes>
#include <cstddef>
#include <cstdint>
#include <map>
#include <optional>
#include <string>
#include <vector>
namespace bpftime
{
namespace verifier
{
std::optional<std::string> verify_ebpf_program(const uint64_t *raw_inst,
size_t num_inst,
const std::string &section_name);

struct BpftimeMapDescriptor {
int original_fd;
uint32_t type; // Platform-specific type value in ELF file.
unsigned int key_size;
unsigned int value_size;
unsigned int max_entries;
unsigned int inner_map_fd;
};

typedef enum {
EBPF_RETURN_TYPE_INTEGER = 0,
EBPF_RETURN_TYPE_PTR_TO_MAP_VALUE_OR_NULL,
EBPF_RETURN_TYPE_INTEGER_OR_NO_RETURN_IF_SUCCEED,
EBPF_RETURN_TYPE_UNSUPPORTED,
} bpftime_return_type_t;

typedef enum {
EBPF_ARGUMENT_TYPE_DONTCARE = 0,
EBPF_ARGUMENT_TYPE_ANYTHING, // All values are valid, e.g., 64-bit
// flags.
EBPF_ARGUMENT_TYPE_CONST_SIZE,
EBPF_ARGUMENT_TYPE_CONST_SIZE_OR_ZERO,
EBPF_ARGUMENT_TYPE_PTR_TO_CTX,
EBPF_ARGUMENT_TYPE_PTR_TO_MAP,
EBPF_ARGUMENT_TYPE_PTR_TO_MAP_OF_PROGRAMS,
EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY,
EBPF_ARGUMENT_TYPE_PTR_TO_MAP_VALUE,
EBPF_ARGUMENT_TYPE_PTR_TO_READABLE_MEM, // Memory must have been
// initialized.
EBPF_ARGUMENT_TYPE_PTR_TO_READABLE_MEM_OR_NULL,
EBPF_ARGUMENT_TYPE_PTR_TO_WRITABLE_MEM,
EBPF_ARGUMENT_TYPE_UNSUPPORTED,
} bpftime_argument_type_t;

struct BpftimeHelperProrotype {
const char *name;

// The return value is returned in register R0.
bpftime_return_type_t return_type;

// Arguments are passed in registers R1 to R5.
bpftime_argument_type_t argument_type[5];
};

void set_available_helpers(const std::vector<int32_t> &helpers);

void set_non_kernel_helpers(
const std::map<int32_t, BpftimeHelperProrotype> &protos);

void set_map_descriptors(const std::map<int, BpftimeMapDescriptor> &maps);
std::map<int, BpftimeMapDescriptor> get_map_descriptors();
} // namespace verifier
} // namespace bpftime

#endif
17 changes: 17 additions & 0 deletions bpftime-verifier/include/platform-impl.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef _PLATFORM_IMPL_HPP
#define _PLATFORM_IMPL_HPP

#include "spec_type_descriptors.hpp"
#include <cstdint>
#include <vector>
#include <platform.hpp>
namespace bpftime
{
extern ebpf_platform_t bpftime_platform_spec;
extern thread_local std::set<int32_t> usable_helpers;
extern thread_local std::map<int, EbpfMapDescriptor> map_descriptors;
extern thread_local std::map<int32_t, EbpfHelperPrototype> non_kernel_helpers;
std::vector<EbpfMapDescriptor> get_all_map_descriptors();
} // namespace bpftime

#endif
Loading

0 comments on commit e7f7717

Please sign in to comment.