├── .github └── workflows │ ├── codeql.yml │ └── go.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── cilium-ebpf.png ├── editor.go ├── editor_test.go ├── ehids-logo-1.png ├── err.go ├── errors.go ├── examples ├── activated_probes │ ├── .gitignore │ ├── Makefile │ ├── ebpf │ │ ├── include │ │ │ ├── bpf.h │ │ │ ├── bpf_helpers.h │ │ │ └── bpf_map.h │ │ └── main.c │ ├── main.go │ ├── probe.go │ └── utils.go ├── clone_vs_add_hook │ ├── .gitignore │ ├── Makefile │ ├── demo.go │ ├── ebpf │ │ ├── include │ │ │ ├── bpf.h │ │ │ ├── bpf_helpers.h │ │ │ └── bpf_map.h │ │ └── main.c │ ├── main.go │ ├── probe.go │ └── utils.go ├── instruction_patching │ ├── Makefile │ ├── bin │ │ └── .gitkeep │ ├── ebpf │ │ ├── include │ │ │ ├── bpf.h │ │ │ ├── bpf_helpers.h │ │ │ └── bpf_map.h │ │ └── main.c │ ├── main.go │ ├── probe.go │ └── utils.go ├── link_pinning │ ├── .gitignore │ ├── Makefile │ ├── ebpf │ │ ├── include │ │ │ ├── bpf.h │ │ │ └── bpf_helpers.h │ │ └── main.c │ ├── main.go │ ├── probe.go │ └── utils.go ├── map_rewrite_vs_map_router │ ├── .gitignore │ ├── Makefile │ ├── demo.go │ ├── ebpf │ │ ├── include │ │ │ ├── bpf.h │ │ │ ├── bpf_helpers.h │ │ │ └── bpf_map.h │ │ ├── prog1.c │ │ └── prog2.c │ ├── main.go │ ├── probe.go │ └── utils.go ├── mapspec_editor │ ├── .gitignore │ ├── Makefile │ ├── ebpf │ │ ├── include │ │ │ ├── bpf.h │ │ │ ├── bpf_helpers.h │ │ │ └── bpf_map.h │ │ └── main.c │ ├── main.go │ ├── probe.go │ └── utils.go ├── object_pinning │ ├── .gitignore │ ├── Makefile │ ├── ebpf │ │ ├── include │ │ │ ├── bpf.h │ │ │ ├── bpf_helpers.h │ │ │ └── bpf_map.h │ │ └── main.c │ ├── main.go │ ├── probe.go │ └── utils.go ├── program_router │ ├── .gitignore │ ├── Makefile │ ├── demo.go │ ├── ebpf │ │ ├── include │ │ │ ├── bpf.h │ │ │ ├── bpf_helpers.h │ │ │ └── bpf_map.h │ │ ├── prog1.c │ │ └── prog2.c │ ├── main.go │ ├── probe.go │ └── utils.go ├── programs │ ├── cgroup │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── ebpf │ │ │ ├── include │ │ │ │ ├── bpf.h │ │ │ │ └── bpf_helpers.h │ │ │ └── main.c │ │ ├── main.go │ │ ├── probe.go │ │ └── utils.go │ ├── kprobe │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── ebpf │ │ │ ├── include │ │ │ │ ├── bpf.h │ │ │ │ └── bpf_helpers.h │ │ │ └── main.c │ │ ├── main.go │ │ ├── probe.go │ │ └── utils.go │ ├── lsm │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── ebpf │ │ │ ├── include │ │ │ │ ├── bpf.h │ │ │ │ └── bpf_helpers.h │ │ │ └── main.c │ │ ├── main.go │ │ ├── probe.go │ │ └── utils.go │ ├── rawtracepoint │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── ebpf │ │ │ ├── include │ │ │ │ ├── bpf.h │ │ │ │ └── bpf_helpers.h │ │ │ └── main.c │ │ ├── main.go │ │ ├── probe.go │ │ └── utils.go │ ├── socket │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── ebpf │ │ │ ├── include │ │ │ │ ├── bpf.h │ │ │ │ └── bpf_helpers.h │ │ │ └── main.c │ │ ├── main.go │ │ ├── probe.go │ │ └── utils.go │ ├── sockops │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── ebpf │ │ │ ├── include │ │ │ │ ├── bpf.h │ │ │ │ └── bpf_helpers.h │ │ │ └── main.c │ │ ├── main.go │ │ ├── probe.go │ │ └── utils.go │ ├── tc │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── ebpf │ │ │ ├── include │ │ │ │ ├── bpf.h │ │ │ │ └── bpf_helpers.h │ │ │ └── main.c │ │ ├── main.go │ │ ├── probe.go │ │ └── utils.go │ ├── tracepoint │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── ebpf │ │ │ ├── include │ │ │ │ ├── bpf.h │ │ │ │ └── bpf_helpers.h │ │ │ └── main.c │ │ ├── main.go │ │ ├── probe.go │ │ └── utils.go │ ├── uprobe │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── ebpf │ │ │ ├── include │ │ │ │ ├── bpf.h │ │ │ │ └── bpf_helpers.h │ │ │ └── main.c │ │ ├── main.go │ │ ├── probe.go │ │ └── utils.go │ └── xdp │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── ebpf │ │ ├── include │ │ │ ├── bpf.h │ │ │ └── bpf_helpers.h │ │ └── main.c │ │ ├── main.go │ │ ├── probe.go │ │ └── utils.go ├── ringbuf_map │ ├── Makefile │ ├── ebpf │ │ ├── include │ │ │ ├── bpf.h │ │ │ ├── bpf_helpers.h │ │ │ └── bpf_map.h │ │ └── main.c │ ├── main.go │ ├── probe.go │ └── utils.go ├── test.sh └── tests_and_benchmarks │ ├── .gitignore │ ├── Makefile │ ├── ebpf │ ├── include │ │ ├── bpf.h │ │ ├── bpf_helpers.h │ │ └── bpf_map.h │ └── main.c │ ├── main.go │ ├── probe.go │ └── utils.go ├── go.mod ├── go.sum ├── kernel ├── kernel_version.go ├── kernel_version_unsupport.go └── version.go ├── manager.go ├── map.go ├── perf.go ├── probe.go ├── ringbuf.go ├── selectors.go ├── syscalls.go ├── testdata ├── Makefile ├── common.h ├── rewrite.c └── rewrite.elf ├── tracefs.go ├── utils.go └── utils_test.go /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "master" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "master" ] 20 | schedule: 21 | - cron: '27 6 * * 1' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'go' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v2 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 63 | 64 | # If the Autobuild fails above, remove it and uncomment the following three lines. 65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 66 | 67 | # - run: | 68 | # echo "Run, Build Application using script" 69 | # ./location_of_script_within_repo/buildscript.sh 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v2 73 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go-test 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Set up Go 16 | uses: actions/setup-go@v5 17 | with: 18 | go-version: 1.24.1 19 | - name: Install Compilers 20 | run: | 21 | sudo apt-get update 22 | sudo apt-get install --yes build-essential pkgconf libelf-dev llvm clang linux-tools-common linux-tools-generic 23 | go get -u github.com/shuLhan/go-bindata/... 24 | shell: bash 25 | - name: Network Interface 26 | run: | 27 | ip -4 route show 28 | ip -o -4 route show to default 29 | - name: Test 30 | run: | 31 | go test -exec sudo ./... 32 | cd examples/ 33 | sh test.sh 34 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # v0.4.5 (2024-02-02) 4 | ## What's Changed 5 | 6 | **Full Changelog**: https://github.com/gojue/ebpfmanager/compare/v0.4.4...v0.4.5 7 | 8 |
9 | 10 | # v0.4.4 (2023-11-10) 11 | ## What's Changed 12 | * add pinned map flag by @cfc4n in https://github.com/gojue/ebpfmanager/pull/34 13 | * add ringbuf support by @spoock1024 in https://github.com/gojue/ebpfmanager/pull/35 14 | * add kernel version detection to ringbuf map. by @cfc4n in https://github.com/gojue/ebpfmanager/pull/37 15 | 16 | ## New Contributors 17 | * @spoock1024 made their first contribution in https://github.com/gojue/ebpfmanager/pull/35 18 | 19 | **Full Changelog**: https://github.com/gojue/ebpfmanager/compare/v0.4.3...v0.4.4 20 | 21 |
22 | 23 | # v0.4.3 (2023-05-19) 24 | * feat: support SockOps eBPF program. 25 | **Full Changelog**: https://github.com/gojue/ebpfmanager/compare/v0.4.2...v0.4.3 26 | 27 | 28 |
29 | 30 | # v0.4.2 (2023-04-29) 31 | 32 | ## What's Changed 33 | * fixes: concurrent map kallsymsCache. (#27) by @cfc4n in https://github.com/gojue/ebpfmanager/pull/28 34 | * remove deprecated function by @cfc4n in https://github.com/gojue/ebpfmanager/pull/29 35 | * Use /proc/kallsyms for kprobe/kretprobe function name search. (fixes #30) by @cfc4n in https://github.com/gojue/ebpfmanager/pull/31 36 | * feat: supoort uprobe's opts address field. by @cfc4n in https://github.com/gojue/ebpfmanager/pull/32 37 | 38 | 39 | **Full Changelog**: https://github.com/gojue/ebpfmanager/compare/v0.4.1...v0.4.2 40 | 41 |
42 | 43 | # v0.4.0 (2023-01-17) 44 | 45 | - Update cilium/ebpf to v0.10.0 from v0.9.0 . 46 | - sync datedog/ebpf-manager package feature. #26 47 | - update golang version to 1.18.* 48 |
49 | 50 | # v0.3.0 (2022-06-15) 51 | 52 | - Update cilium/ebpf to v0.9.0 from 0.8.1 . 53 | - Add GitHub Actions (codeQL \ go-test) 54 | - 55 | 56 | fixed [#10 type 'Probe' contains 'sync.RWMutex' which is 'sync.Locker'](https://github.com/gojue/ebpfmanager/issues/10) 57 | 58 |
59 | 60 | # v0.2.3 (2022-04-09) 61 | 62 | - Fix. [#1 GetSyscallFnNameWithSymFile memory leak](https://github.com/gojue/ebpfmanager/pull/2) 63 | - Fix format type error. 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | [![](https://godoc.org/github.com/gojue/ebpfmanager?status.svg)](https://godoc.org/github.com/gojue/ebpfmanager) 3 | 4 | 5 | ebpfmanager参照datadog/ebpf/manager包的思想,基于cilium/ebpf实现的ebpf类库封装。 6 | 7 | 相比`cilium/ebpf`实现配置化,自动加载,更具备面向对象思想,且实现了`probe`颗粒的卡开启关闭功能。 相比`datadog/ebpf`,实现了依赖包方式加载`cilium/ebpf` 8 | ,而非fork方式,这点与其期望走的方向一致。且依赖`cilium/ebpf`版本更新到最新v0.9.0。 9 | >Work is underway to convert this library to wrap the upstream library, rather than forking. 10 | 11 | 12 | # 依赖 13 | 14 | * [cilium/ebpf v0.18.0](https://github.com/cilium/ebpf/releases/tag/v0.18.0) 2025-05-18 15 | * [go-bindata](https://github.com/shuLhan/go-bindata/cmd/go-bindata) 用于生成ebpf字节码文件的go包,与`go:embed`类似。 16 | ```shell 17 | go get -d github.com/shuLhan/go-bindata/cmd/go-bindata 18 | ``` 19 | 20 | # 说明 21 | manager与probe是一对多关系。每个probe必须配置`Section`与`EbpfFuncName`两个属性。如果是`k(ret)probe`或`u(ret)probe`,则还需要配置`AttachToFuncName`属性。 22 | ```go 23 | // UID 可选自定义的唯一字符串 24 | UID string 25 | 26 | // Section elf字节码的Section名字,比如SEC("[section]"). 用于识别probe的类型[ku](ret)?probe/xdp/(raw_)?tracepoint/tc等 27 | // 早期datadog/ebpf类库用于manager的collectionSpec.Programs的索引。 28 | // 但cilium/ebpf v0.7.0中,不被返回作为programSpec map作为索引。索引改用MatchFuncName 29 | Section string 30 | 31 | // AttachToFuncName 被HOOK的syscall名字,忽略系统内核版本、CPU位数,比如 mkdirat 会被转换为__x64_sys_mkdirat、__ia32_sys_mkdirat等 32 | // Uprobe时,直接作为挂载的函数名。 33 | // 若不填写,则自动获取 Section 字段的最后一段作为挂载函数名 34 | AttachToFuncName string 35 | 36 | // EbpfFuncName 表示字节码内内核态C函数的名字,取自字节码elf的符号表 37 | EbpfFuncName string 38 | 39 | // funcName 目标hook对象的函数名;私有属性,会自动计算赋值。uprobe中,若为空,则使用offset。 40 | funcName string 41 | ``` 42 | 43 | # 使用方法 44 | 45 | 参考`examples`目录下例子,比如`uprobe` 46 | 47 | ```go 48 | package main 49 | 50 | import ( 51 | "github.com/gojue/ebpfmanager" 52 | "github.com/sirupsen/logrus" 53 | ) 54 | 55 | var m = &manager.Manager{ 56 | Probes: []*manager.Probe{ 57 | { 58 | Section: "uprobe/readline", 59 | EbpfFuncName: "uprobe_readline", 60 | AttachToFuncName: "readline", 61 | BinaryPath: "/usr/bin/bash", 62 | }, 63 | }, 64 | } 65 | 66 | func main() { 67 | // Initialize the manager 68 | if err := m.Init(recoverAssets()); err != nil { 69 | logrus.Fatal(err) 70 | } 71 | 72 | // Start the manager 73 | if err := m.Start(); err != nil { 74 | logrus.Fatal(err) 75 | } 76 | 77 | logrus.Println("successfully started, head over to /sys/kernel/debug/tracing/trace_pipe") 78 | 79 | // Spawn a bash and right a command to trigger the probe 80 | if err := trigger(); err != nil { 81 | logrus.Error(err) 82 | } 83 | 84 | // Close the manager 85 | if err := m.Stop(manager.CleanAll); err != nil { 86 | logrus.Fatal(err) 87 | } 88 | } 89 | ``` 90 | 91 | # 案例项目 92 | 93 | * eCapture : [capture SSL/TLS text content without CA cert using eBPF.](https://github.com/ehids/ecapture) 94 | * eHIDS-Agent : [A Linux Host-based Intrusion Detection System based on eBPF.](https://github.com/ehids/ehids-agent) 95 | 96 | # 注意 97 | 98 | 1. v0.7.0及以后的版本中,ebpf在`loadProgram`函数返回的progs map中,索引已经改为C代码中函数名。 见`elf_reader.go`312行`res[prog.Name] = prog` 99 | ,这点不同于老版本。(老版本是以section名字作为索引) 100 | 2. 在 [datadog/ebpf af587081](https://github.com/DataDog/ebpf/commit/af5870810f0b2c2f9ba996d02db16955de58266f) Nov 17, 101 | 2021 版本上实现本类库。 102 | 103 | # 感谢 104 | 105 | 感谢 [https://jetbrains.com/](https://jetbrains.com/) 的 All Products Pack IDE使用授权。 106 | -------------------------------------------------------------------------------- /cilium-ebpf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gojue/ebpfmanager/80670ed5a287e243e99c6ce5b44333221656201a/cilium-ebpf.png -------------------------------------------------------------------------------- /editor.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "fmt" 5 | "github.com/cilium/ebpf/asm" 6 | ) 7 | 8 | // Editor modifies eBPF instructions. 9 | type Editor struct { 10 | instructions *asm.Instructions 11 | ReferenceOffsets map[string][]int 12 | } 13 | 14 | // Edit creates a new Editor. 15 | // 16 | // The editor retains a reference to insns and modifies its 17 | // contents. 18 | func Edit(insns *asm.Instructions) *Editor { 19 | refs := insns.ReferenceOffsets() 20 | return &Editor{insns, refs} 21 | } 22 | 23 | // RewriteConstant rewrites all loads of a symbol to a constant value. 24 | // 25 | // This is a way to parameterize clang-compiled eBPF byte code at load 26 | // time. 27 | // 28 | // The following macro should be used to access the constant: 29 | // 30 | // #define LOAD_CONSTANT(param, var) asm("%0 = " param " ll" : "=r"(var)) 31 | // 32 | // int xdp() { 33 | // bool my_constant; 34 | // LOAD_CONSTANT("SYMBOL_NAME", my_constant); 35 | // 36 | // if (my_constant) ... 37 | // 38 | // Caveats: 39 | // - The symbol name you pick must be unique 40 | // 41 | // - Failing to rewrite a symbol will not result in an error, 42 | // 0 will be loaded instead (subject to change) 43 | // 44 | // Use IsUnreferencedSymbol if you want to rewrite potentially 45 | // unused symbols. 46 | func (ed *Editor) RewriteConstant(symbol string, value uint64) error { 47 | indices := ed.ReferenceOffsets[symbol] 48 | if len(indices) == 0 { 49 | return &unreferencedSymbolError{symbol} 50 | } 51 | 52 | ldDWImm := asm.LoadImmOp(asm.DWord) 53 | for _, index := range indices { 54 | load := &(*ed.instructions)[index] 55 | if load.OpCode != ldDWImm { 56 | return fmt.Errorf("symbol %v: load: found %v instead of %v", symbol, load.OpCode, ldDWImm) 57 | } 58 | 59 | load.Constant = int64(value) 60 | } 61 | return nil 62 | } 63 | 64 | type unreferencedSymbolError struct { 65 | symbol string 66 | } 67 | 68 | func (use *unreferencedSymbolError) Error() string { 69 | return fmt.Sprintf("unreferenced symbol %s", use.symbol) 70 | } 71 | 72 | // IsUnreferencedSymbol returns true if err was caused by 73 | // an unreferenced symbol. 74 | func IsUnreferencedSymbol(err error) bool { 75 | _, ok := err.(*unreferencedSymbolError) 76 | return ok 77 | } 78 | -------------------------------------------------------------------------------- /editor_test.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "fmt" 5 | "github.com/cilium/ebpf/rlimit" 6 | "math" 7 | "testing" 8 | 9 | "github.com/cilium/ebpf" 10 | "github.com/cilium/ebpf/asm" 11 | ) 12 | 13 | // ExampleEditor_rewriteConstant shows how to change constants in 14 | // compiled eBPF byte code. 15 | // 16 | // The C should look something like this: 17 | // 18 | // #define LOAD_CONSTANT(param, var) asm("%0 = " param " ll" : "=r"(var)) 19 | // 20 | // int xdp() { 21 | // bool my_constant; 22 | // LOAD_CONSTANT("SYMBOL_NAME", my_constant); 23 | // 24 | // if (my_constant) ... 25 | func ExampleEditor_rewriteConstant() { 26 | // This assembly is roughly equivalent to what clang 27 | // would emit for the C above. 28 | insns := asm.Instructions{ 29 | asm.LoadImm(asm.R0, 0, asm.DWord).WithReference("my_ret"), 30 | asm.Return(), 31 | } 32 | 33 | editor := Edit(&insns) 34 | if err := editor.RewriteConstant("my_ret", 42); err != nil { 35 | panic(err) 36 | } 37 | 38 | fmt.Printf("%0.0s", insns) 39 | 40 | // Output: 0: LdImmDW dst: r0 imm: 42 41 | // 2: Exit 42 | } 43 | 44 | func TestEditorRewriteConstant(t *testing.T) { 45 | 46 | if err := rlimit.RemoveMemlock(); err != nil { 47 | t.Fatal(err) 48 | } 49 | 50 | spec, err := ebpf.LoadCollectionSpec("testdata/rewrite.elf") 51 | if err != nil { 52 | t.Fatal(err) 53 | } 54 | 55 | progSpec := spec.Programs["rewrite"] 56 | editor := Edit(&progSpec.Instructions) 57 | 58 | if err := editor.RewriteConstant("constant", 0x01); err != nil { 59 | t.Fatal(err) 60 | } 61 | 62 | if err := editor.RewriteConstant("bogus", 0x01); !IsUnreferencedSymbol(err) { 63 | t.Error("Rewriting unreferenced symbol doesn't return appropriate error") 64 | } 65 | 66 | t.Log(progSpec.Instructions) 67 | 68 | prog, err := ebpf.NewProgram(progSpec) 69 | if err != nil { 70 | t.Fatal(err) 71 | } 72 | defer prog.Close() 73 | 74 | ret, _, err := prog.Test(make([]byte, 15)) 75 | if err != nil { 76 | t.Fatal(err) 77 | } 78 | 79 | const N = 1 // number of rewrites 80 | if expected := uint32(1<= 5.8.0") 7 | ErrLSMNotSupported = errors.New("LSM is not supported on this kernel, need kernel version >= 5.7.0") 8 | ) 9 | -------------------------------------------------------------------------------- /examples/activated_probes/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | ebpf/bin/ 3 | -------------------------------------------------------------------------------- /examples/activated_probes/Makefile: -------------------------------------------------------------------------------- 1 | all: build-ebpf build run 2 | 3 | build-ebpf: 4 | mkdir -p ebpf/bin 5 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 6 | -Wno-unused-value \ 7 | -Wno-pointer-sign \ 8 | -Wno-compare-distinct-pointer-types \ 9 | -Wunused \ 10 | -Wall \ 11 | -Werror \ 12 | -I/lib/modules/$$(uname -r)/build/include \ 13 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 14 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 15 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 16 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 17 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 18 | -O2 -emit-llvm \ 19 | ebpf/main.c \ 20 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe.o 21 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg main -prefix "ebpf/bin" -o "probe.go" "ebpf/bin/probe.o" 22 | 23 | build: 24 | go build -o bin/main . 25 | 26 | run: 27 | sudo bin/main 28 | -------------------------------------------------------------------------------- /examples/activated_probes/ebpf/include/bpf_helpers.h: -------------------------------------------------------------------------------- 1 | #ifndef __BPF_HELPERS_H 2 | #define __BPF_HELPERS_H 3 | 4 | #define bpf_printk(fmt, ...) \ 5 | ({ \ 6 | char ____fmt[] = fmt; \ 7 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 8 | ##__VA_ARGS__); \ 9 | }) 10 | 11 | /* helper macro to place programs, maps, license in 12 | * different sections in elf_bpf file. Section names 13 | * are interpreted by elf_bpf loader 14 | */ 15 | #define SEC(NAME) __attribute__((section(NAME), used)) 16 | 17 | /* helper functions called from eBPF programs written in C */ 18 | static void *(*bpf_map_lookup_elem)(void *map, void *key) = 19 | (void *)BPF_FUNC_map_lookup_elem; 20 | static int (*bpf_map_update_elem)(void *map, void *key, void *value, 21 | unsigned long long flags) = 22 | (void *)BPF_FUNC_map_update_elem; 23 | static int (*bpf_map_delete_elem)(void *map, void *key) = 24 | (void *)BPF_FUNC_map_delete_elem; 25 | static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) = 26 | (void *)BPF_FUNC_probe_read; 27 | static unsigned long long (*bpf_ktime_get_ns)(void) = 28 | (void *)BPF_FUNC_ktime_get_ns; 29 | static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = 30 | (void *)BPF_FUNC_trace_printk; 31 | static unsigned long long (*bpf_get_smp_processor_id)(void) = 32 | (void *)BPF_FUNC_get_smp_processor_id; 33 | static unsigned long long (*bpf_get_current_pid_tgid)(void) = 34 | (void *)BPF_FUNC_get_current_pid_tgid; 35 | static unsigned long long (*bpf_get_current_uid_gid)(void) = 36 | (void *)BPF_FUNC_get_current_uid_gid; 37 | static int (*bpf_get_current_comm)(void *buf, int buf_size) = 38 | (void *)BPF_FUNC_get_current_comm; 39 | static int (*bpf_perf_event_read)(void *map, int index) = 40 | (void *)BPF_FUNC_perf_event_read; 41 | static int (*bpf_clone_redirect)(void *ctx, int ifindex, int flags) = 42 | (void *)BPF_FUNC_clone_redirect; 43 | static int (*bpf_redirect)(int ifindex, int flags) = 44 | (void *)BPF_FUNC_redirect; 45 | static int (*bpf_perf_event_output)(void *ctx, void *map, 46 | unsigned long long flags, void *data, 47 | int size) = 48 | (void *)BPF_FUNC_perf_event_output; 49 | static int (*bpf_skb_get_tunnel_key)(void *ctx, void *key, int size, int flags) = 50 | (void *)BPF_FUNC_skb_get_tunnel_key; 51 | static int (*bpf_skb_set_tunnel_key)(void *ctx, void *key, int size, int flags) = 52 | (void *)BPF_FUNC_skb_set_tunnel_key; 53 | static unsigned long long (*bpf_get_prandom_u32)(void) = 54 | (void *)BPF_FUNC_get_prandom_u32; 55 | 56 | /* llvm builtin functions that eBPF C program may use to 57 | * emit BPF_LD_ABS and BPF_LD_IND instructions 58 | */ 59 | struct sk_buff; 60 | unsigned long long load_byte(void *skb, 61 | unsigned long long off) asm("llvm.bpf.load.byte"); 62 | unsigned long long load_half(void *skb, 63 | unsigned long long off) asm("llvm.bpf.load.half"); 64 | unsigned long long load_word(void *skb, 65 | unsigned long long off) asm("llvm.bpf.load.word"); 66 | 67 | /* a helper structure used by eBPF C program 68 | * to describe map attributes to elf_bpf loader 69 | */ 70 | #define BUF_SIZE_MAP_NS 256 71 | 72 | // struct bpf_map_def 73 | // { 74 | // unsigned int type; 75 | // unsigned int key_size; 76 | // unsigned int value_size; 77 | // unsigned int max_entries; 78 | // unsigned int map_flags; 79 | // unsigned int pinning; 80 | // char namespace[BUF_SIZE_MAP_NS]; 81 | // }; 82 | 83 | static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = 84 | (void *)BPF_FUNC_skb_store_bytes; 85 | static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) = 86 | (void *)BPF_FUNC_l3_csum_replace; 87 | static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) = 88 | (void *)BPF_FUNC_l4_csum_replace; 89 | 90 | #if defined(__x86_64__) 91 | 92 | #define PT_REGS_PARM1(x) ((x)->di) 93 | #define PT_REGS_PARM2(x) ((x)->si) 94 | #define PT_REGS_PARM3(x) ((x)->dx) 95 | #define PT_REGS_PARM4(x) ((x)->cx) 96 | #define PT_REGS_PARM5(x) ((x)->r8) 97 | #define PT_REGS_RET(x) ((x)->sp) 98 | #define PT_REGS_FP(x) ((x)->bp) 99 | #define PT_REGS_RC(x) ((x)->ax) 100 | #define PT_REGS_SP(x) ((x)->sp) 101 | #define PT_REGS_IP(x) ((x)->ip) 102 | 103 | #elif defined(__s390x__) 104 | 105 | #define PT_REGS_PARM1(x) ((x)->gprs[2]) 106 | #define PT_REGS_PARM2(x) ((x)->gprs[3]) 107 | #define PT_REGS_PARM3(x) ((x)->gprs[4]) 108 | #define PT_REGS_PARM4(x) ((x)->gprs[5]) 109 | #define PT_REGS_PARM5(x) ((x)->gprs[6]) 110 | #define PT_REGS_RET(x) ((x)->gprs[14]) 111 | #define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */ 112 | #define PT_REGS_RC(x) ((x)->gprs[2]) 113 | #define PT_REGS_SP(x) ((x)->gprs[15]) 114 | #define PT_REGS_IP(x) ((x)->ip) 115 | 116 | #elif defined(__aarch64__) 117 | 118 | #define PT_REGS_PARM1(x) ((x)->regs[0]) 119 | #define PT_REGS_PARM2(x) ((x)->regs[1]) 120 | #define PT_REGS_PARM3(x) ((x)->regs[2]) 121 | #define PT_REGS_PARM4(x) ((x)->regs[3]) 122 | #define PT_REGS_PARM5(x) ((x)->regs[4]) 123 | #define PT_REGS_RET(x) ((x)->regs[30]) 124 | #define PT_REGS_FP(x) ((x)->regs[29]) /* Works only with CONFIG_FRAME_POINTER */ 125 | #define PT_REGS_RC(x) ((x)->regs[0]) 126 | #define PT_REGS_SP(x) ((x)->sp) 127 | #define PT_REGS_IP(x) ((x)->pc) 128 | 129 | #elif defined(__powerpc__) 130 | 131 | #define PT_REGS_PARM1(x) ((x)->gpr[3]) 132 | #define PT_REGS_PARM2(x) ((x)->gpr[4]) 133 | #define PT_REGS_PARM3(x) ((x)->gpr[5]) 134 | #define PT_REGS_PARM4(x) ((x)->gpr[6]) 135 | #define PT_REGS_PARM5(x) ((x)->gpr[7]) 136 | #define PT_REGS_RC(x) ((x)->gpr[3]) 137 | #define PT_REGS_SP(x) ((x)->sp) 138 | #define PT_REGS_IP(x) ((x)->nip) 139 | 140 | #endif 141 | 142 | #ifdef __powerpc__ 143 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) 144 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP 145 | #else 146 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) 147 | #define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), \ 148 | (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) 149 | #endif 150 | 151 | #endif 152 | -------------------------------------------------------------------------------- /examples/activated_probes/ebpf/include/bpf_map.h: -------------------------------------------------------------------------------- 1 | #define BUF_SIZE_MAP_NS 256 2 | 3 | typedef struct bpf_map_def { 4 | unsigned int type; 5 | unsigned int key_size; 6 | unsigned int value_size; 7 | unsigned int max_entries; 8 | unsigned int map_flags; 9 | unsigned int inner_map_idx; 10 | unsigned int pinning; 11 | char namespace[BUF_SIZE_MAP_NS]; 12 | } bpf_map_def; 13 | 14 | enum bpf_pin_type { 15 | PIN_NONE = 0, 16 | PIN_OBJECT_NS, 17 | PIN_GLOBAL_NS, 18 | PIN_CUSTOM_NS, 19 | }; 20 | -------------------------------------------------------------------------------- /examples/activated_probes/ebpf/main.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_map.h" 3 | #include "include/bpf_helpers.h" 4 | 5 | SEC("kprobe/vfs_mkdir") 6 | int kprobe_vfs_mkdir(void *ctx) 7 | { 8 | bpf_printk("mkdir (vfs hook point)\n"); 9 | return 0; 10 | }; 11 | 12 | SEC("kprobe/utimes_common") 13 | int kprobe_utimes_common(void *ctx) 14 | { 15 | bpf_printk("utimes_common\n"); 16 | return 0; 17 | }; 18 | 19 | SEC("kprobe/vfs_opennnnnn") 20 | int kprobe_open(void *ctx) 21 | { 22 | bpf_printk("vfs_open\n"); 23 | return 0; 24 | }; 25 | 26 | SEC("kprobe/exclude") 27 | int kprobe_exclude(void *ctx) 28 | { 29 | bpf_printk("exclude\n"); 30 | return 0; 31 | }; 32 | 33 | char _license[] SEC("license") = "GPL"; 34 | __u32 _version SEC("version") = 0xFFFFFFFE; 35 | -------------------------------------------------------------------------------- /examples/activated_probes/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "os" 8 | 9 | "github.com/sirupsen/logrus" 10 | ) 11 | 12 | // recoverAssets - Recover ebpf asset 13 | func recoverAssets() io.ReaderAt { 14 | buf, err := Asset("/probe.o") 15 | if err != nil { 16 | logrus.Fatal(fmt.Errorf("error:%v, %s",err, "couldn't find asset")) 17 | } 18 | return bytes.NewReader(buf) 19 | } 20 | 21 | // trigger - Creates and then removes a tmp folder to trigger the probes 22 | func trigger() error { 23 | logrus.Println("Generating events to trigger the probes ...") 24 | // Creating a tmp directory to trigger the probes 25 | tmpDir := "/tmp/test_folder" 26 | logrus.Printf("creating %v", tmpDir) 27 | err := os.MkdirAll(tmpDir, 0666) 28 | if err != nil { 29 | return err 30 | } 31 | 32 | // Removing a tmp directory to trigger the probes 33 | logrus.Printf("removing %v", tmpDir) 34 | return os.RemoveAll(tmpDir) 35 | } 36 | 37 | -------------------------------------------------------------------------------- /examples/clone_vs_add_hook/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | ebpf/bin/ 3 | -------------------------------------------------------------------------------- /examples/clone_vs_add_hook/Makefile: -------------------------------------------------------------------------------- 1 | all: build-ebpf build run 2 | 3 | build-ebpf: 4 | mkdir -p ebpf/bin 5 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 6 | -Wno-unused-value \ 7 | -Wno-pointer-sign \ 8 | -Wno-compare-distinct-pointer-types \ 9 | -Wunused \ 10 | -Wall \ 11 | -Werror \ 12 | -I/lib/modules/$$(uname -r)/build/include \ 13 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 14 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 15 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 16 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 17 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 18 | -O2 -emit-llvm \ 19 | ebpf/main.c \ 20 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe.o 21 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg main -prefix "ebpf/bin" -o "probe.go" "ebpf/bin/probe.o" 22 | 23 | build: 24 | go build -o bin/main . 25 | 26 | run: 27 | sudo bin/main 28 | -------------------------------------------------------------------------------- /examples/clone_vs_add_hook/demo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/sirupsen/logrus" 5 | 6 | "github.com/gojue/ebpfmanager" 7 | ) 8 | 9 | func demoClone() error { 10 | logrus.Println("CLONE DEMO") 11 | // Clone kprobe/vfs_open program, edit its constant and load a new probe. This will essentially create a new program 12 | // and you should see a new line in /sys/kernel/debug/tracing/kprobe_events. 13 | newProbe := manager.Probe{ 14 | UID: "MySeconHook", 15 | Section: "kprobe/vfs_mkdir", 16 | EbpfFuncName: "kprobe_vfs_mkdir", 17 | AttachToFuncName: "vfs_mkdir", 18 | } 19 | 20 | mkdirCloneEditors := []manager.ConstantEditor{ 21 | { 22 | Name: "my_constant", 23 | Value: uint64(42), 24 | ProbeIdentificationPairs: []manager.ProbeIdentificationPair{ 25 | newProbe.GetIdentificationPair(), 26 | }, 27 | }, 28 | } 29 | 30 | err := m.CloneProgram("MyFirstHook", &newProbe, mkdirCloneEditors, nil) 31 | if err != nil { 32 | return err 33 | } 34 | 35 | return trigger() 36 | } 37 | 38 | func demoAddHook() error { 39 | logrus.Println("ADD HOOK DEMO") 40 | // Add a new hook point to the kprobe/vfs_mkdir program. The program was initially loaded but not attached. This will 41 | // not create a copy of the program, it will just add a new hook point. This can be donne multiple times. 42 | firstRmdir := manager.Probe{ 43 | UID: "FirstRmdir", 44 | Section: "kprobe/vfs_rmdir", 45 | AttachToFuncName: "vfs_rmdir", 46 | EbpfFuncName: "kprobe_vfs_rmdir", 47 | } 48 | err := m.AddHook("", &firstRmdir) 49 | if err != nil { 50 | logrus.Fatal(err) 51 | } 52 | 53 | secondRmdir := manager.Probe{ 54 | UID: "SecondRmdir", 55 | Section: "kprobe/vfs_rmdir", 56 | AttachToFuncName: "vfs_rmdir", 57 | EbpfFuncName: "kprobe_vfs_rmdir", 58 | } 59 | err = m.AddHook("", &secondRmdir) 60 | if err != nil { 61 | return err 62 | } 63 | 64 | if err = trigger(); err != nil { 65 | return err 66 | } 67 | 68 | logrus.Println("DETACH HOOK DEMO") 69 | 70 | // Detaching a hook point does not close the underlying eBPF program, which means that the other hook points are 71 | // still working 72 | err = m.DetachHook(secondRmdir.Section, secondRmdir.UID) 73 | if err != nil { 74 | return err 75 | } 76 | 77 | return trigger() 78 | } 79 | -------------------------------------------------------------------------------- /examples/clone_vs_add_hook/ebpf/include/bpf_helpers.h: -------------------------------------------------------------------------------- 1 | #ifndef __BPF_HELPERS_H 2 | #define __BPF_HELPERS_H 3 | 4 | #define bpf_printk(fmt, ...) \ 5 | ({ \ 6 | char ____fmt[] = fmt; \ 7 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 8 | ##__VA_ARGS__); \ 9 | }) 10 | 11 | /* helper macro to place programs, maps, license in 12 | * different sections in elf_bpf file. Section names 13 | * are interpreted by elf_bpf loader 14 | */ 15 | #define SEC(NAME) __attribute__((section(NAME), used)) 16 | 17 | /* helper functions called from eBPF programs written in C */ 18 | static void *(*bpf_map_lookup_elem)(void *map, void *key) = 19 | (void *)BPF_FUNC_map_lookup_elem; 20 | static int (*bpf_map_update_elem)(void *map, void *key, void *value, 21 | unsigned long long flags) = 22 | (void *)BPF_FUNC_map_update_elem; 23 | static int (*bpf_map_delete_elem)(void *map, void *key) = 24 | (void *)BPF_FUNC_map_delete_elem; 25 | static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) = 26 | (void *)BPF_FUNC_probe_read; 27 | static unsigned long long (*bpf_ktime_get_ns)(void) = 28 | (void *)BPF_FUNC_ktime_get_ns; 29 | static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = 30 | (void *)BPF_FUNC_trace_printk; 31 | static unsigned long long (*bpf_get_smp_processor_id)(void) = 32 | (void *)BPF_FUNC_get_smp_processor_id; 33 | static unsigned long long (*bpf_get_current_pid_tgid)(void) = 34 | (void *)BPF_FUNC_get_current_pid_tgid; 35 | static unsigned long long (*bpf_get_current_uid_gid)(void) = 36 | (void *)BPF_FUNC_get_current_uid_gid; 37 | static int (*bpf_get_current_comm)(void *buf, int buf_size) = 38 | (void *)BPF_FUNC_get_current_comm; 39 | static int (*bpf_perf_event_read)(void *map, int index) = 40 | (void *)BPF_FUNC_perf_event_read; 41 | static int (*bpf_clone_redirect)(void *ctx, int ifindex, int flags) = 42 | (void *)BPF_FUNC_clone_redirect; 43 | static int (*bpf_redirect)(int ifindex, int flags) = 44 | (void *)BPF_FUNC_redirect; 45 | static int (*bpf_perf_event_output)(void *ctx, void *map, 46 | unsigned long long flags, void *data, 47 | int size) = 48 | (void *)BPF_FUNC_perf_event_output; 49 | static int (*bpf_skb_get_tunnel_key)(void *ctx, void *key, int size, int flags) = 50 | (void *)BPF_FUNC_skb_get_tunnel_key; 51 | static int (*bpf_skb_set_tunnel_key)(void *ctx, void *key, int size, int flags) = 52 | (void *)BPF_FUNC_skb_set_tunnel_key; 53 | static unsigned long long (*bpf_get_prandom_u32)(void) = 54 | (void *)BPF_FUNC_get_prandom_u32; 55 | 56 | /* llvm builtin functions that eBPF C program may use to 57 | * emit BPF_LD_ABS and BPF_LD_IND instructions 58 | */ 59 | struct sk_buff; 60 | unsigned long long load_byte(void *skb, 61 | unsigned long long off) asm("llvm.bpf.load.byte"); 62 | unsigned long long load_half(void *skb, 63 | unsigned long long off) asm("llvm.bpf.load.half"); 64 | unsigned long long load_word(void *skb, 65 | unsigned long long off) asm("llvm.bpf.load.word"); 66 | 67 | /* a helper structure used by eBPF C program 68 | * to describe map attributes to elf_bpf loader 69 | */ 70 | #define BUF_SIZE_MAP_NS 256 71 | 72 | // struct bpf_map_def 73 | // { 74 | // unsigned int type; 75 | // unsigned int key_size; 76 | // unsigned int value_size; 77 | // unsigned int max_entries; 78 | // unsigned int map_flags; 79 | // unsigned int pinning; 80 | // char namespace[BUF_SIZE_MAP_NS]; 81 | // }; 82 | 83 | static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = 84 | (void *)BPF_FUNC_skb_store_bytes; 85 | static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) = 86 | (void *)BPF_FUNC_l3_csum_replace; 87 | static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) = 88 | (void *)BPF_FUNC_l4_csum_replace; 89 | 90 | #if defined(__x86_64__) 91 | 92 | #define PT_REGS_PARM1(x) ((x)->di) 93 | #define PT_REGS_PARM2(x) ((x)->si) 94 | #define PT_REGS_PARM3(x) ((x)->dx) 95 | #define PT_REGS_PARM4(x) ((x)->cx) 96 | #define PT_REGS_PARM5(x) ((x)->r8) 97 | #define PT_REGS_RET(x) ((x)->sp) 98 | #define PT_REGS_FP(x) ((x)->bp) 99 | #define PT_REGS_RC(x) ((x)->ax) 100 | #define PT_REGS_SP(x) ((x)->sp) 101 | #define PT_REGS_IP(x) ((x)->ip) 102 | 103 | #elif defined(__s390x__) 104 | 105 | #define PT_REGS_PARM1(x) ((x)->gprs[2]) 106 | #define PT_REGS_PARM2(x) ((x)->gprs[3]) 107 | #define PT_REGS_PARM3(x) ((x)->gprs[4]) 108 | #define PT_REGS_PARM4(x) ((x)->gprs[5]) 109 | #define PT_REGS_PARM5(x) ((x)->gprs[6]) 110 | #define PT_REGS_RET(x) ((x)->gprs[14]) 111 | #define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */ 112 | #define PT_REGS_RC(x) ((x)->gprs[2]) 113 | #define PT_REGS_SP(x) ((x)->gprs[15]) 114 | #define PT_REGS_IP(x) ((x)->ip) 115 | 116 | #elif defined(__aarch64__) 117 | 118 | #define PT_REGS_PARM1(x) ((x)->regs[0]) 119 | #define PT_REGS_PARM2(x) ((x)->regs[1]) 120 | #define PT_REGS_PARM3(x) ((x)->regs[2]) 121 | #define PT_REGS_PARM4(x) ((x)->regs[3]) 122 | #define PT_REGS_PARM5(x) ((x)->regs[4]) 123 | #define PT_REGS_RET(x) ((x)->regs[30]) 124 | #define PT_REGS_FP(x) ((x)->regs[29]) /* Works only with CONFIG_FRAME_POINTER */ 125 | #define PT_REGS_RC(x) ((x)->regs[0]) 126 | #define PT_REGS_SP(x) ((x)->sp) 127 | #define PT_REGS_IP(x) ((x)->pc) 128 | 129 | #elif defined(__powerpc__) 130 | 131 | #define PT_REGS_PARM1(x) ((x)->gpr[3]) 132 | #define PT_REGS_PARM2(x) ((x)->gpr[4]) 133 | #define PT_REGS_PARM3(x) ((x)->gpr[5]) 134 | #define PT_REGS_PARM4(x) ((x)->gpr[6]) 135 | #define PT_REGS_PARM5(x) ((x)->gpr[7]) 136 | #define PT_REGS_RC(x) ((x)->gpr[3]) 137 | #define PT_REGS_SP(x) ((x)->sp) 138 | #define PT_REGS_IP(x) ((x)->nip) 139 | 140 | #endif 141 | 142 | #ifdef __powerpc__ 143 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) 144 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP 145 | #else 146 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) 147 | #define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), \ 148 | (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) 149 | #endif 150 | 151 | #endif 152 | -------------------------------------------------------------------------------- /examples/clone_vs_add_hook/ebpf/include/bpf_map.h: -------------------------------------------------------------------------------- 1 | #define BUF_SIZE_MAP_NS 256 2 | 3 | typedef struct bpf_map_def { 4 | unsigned int type; 5 | unsigned int key_size; 6 | unsigned int value_size; 7 | unsigned int max_entries; 8 | unsigned int map_flags; 9 | unsigned int inner_map_idx; 10 | unsigned int pinning; 11 | char namespace[BUF_SIZE_MAP_NS]; 12 | } bpf_map_def; 13 | 14 | enum bpf_pin_type { 15 | PIN_NONE = 0, 16 | PIN_OBJECT_NS, 17 | PIN_GLOBAL_NS, 18 | PIN_CUSTOM_NS, 19 | }; 20 | -------------------------------------------------------------------------------- /examples/clone_vs_add_hook/ebpf/main.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_map.h" 3 | #include "include/bpf_helpers.h" 4 | 5 | #define LOAD_CONSTANT(param, var) asm("%0 = " param " ll" : "=r"(var)) 6 | 7 | __attribute__((always_inline)) static u64 load_my_constant() { 8 | u64 my_constant = 0; 9 | LOAD_CONSTANT("my_constant", my_constant); 10 | return my_constant; 11 | } 12 | 13 | struct bpf_map_def SEC("maps/my_constants") my_constants = { 14 | .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, 15 | .key_size = 0, 16 | .value_size = 0, 17 | .max_entries = 0, 18 | .pinning = PIN_NONE, 19 | .namespace = "", 20 | }; 21 | 22 | SEC("kprobe/vfs_mkdir") 23 | int kprobe_vfs_mkdir(void *ctx) 24 | { 25 | u64 my_constant = load_my_constant(); 26 | bpf_printk("mkdir (vfs hook point) | my_constant = %d\n", load_my_constant()); 27 | 28 | // Send my constant to user space 29 | u32 cpu = bpf_get_smp_processor_id(); 30 | bpf_perf_event_output(ctx, &my_constants, cpu, &my_constant, sizeof(my_constant)); 31 | return 0; 32 | }; 33 | 34 | SEC("kprobe/vfs_rmdir") 35 | int kprobe_vfs_rmdir(void *ctx) 36 | { 37 | u64 my_constant = load_my_constant(); 38 | bpf_printk("rmdir (vfs hook point) | my_constant = %d\n", load_my_constant()); 39 | 40 | // Send my constant to user space 41 | u32 cpu = bpf_get_smp_processor_id(); 42 | bpf_perf_event_output(ctx, &my_constants, cpu, &my_constant, sizeof(my_constant)); 43 | return 0; 44 | }; 45 | 46 | SEC("kretprobe/mkdir") 47 | int kretpobe_mkdir(void *ctx) 48 | { 49 | bpf_printk("mkdir return (syscall hook point)\n"); 50 | return 0; 51 | } 52 | 53 | char _license[] SEC("license") = "GPL"; 54 | __u32 _version SEC("version") = 0xFFFFFFFE; 55 | -------------------------------------------------------------------------------- /examples/clone_vs_add_hook/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/gojue/ebpfmanager" 5 | "github.com/sirupsen/logrus" 6 | ) 7 | 8 | var m = &manager.Manager{ 9 | Probes: []*manager.Probe{ 10 | &manager.Probe{ 11 | UID: "MyFirstHook", 12 | Section: "kprobe/vfs_mkdir", 13 | AttachToFuncName: "vfs_mkdir", 14 | EbpfFuncName: "kprobe_vfs_mkdir", 15 | }, 16 | &manager.Probe{ 17 | UID: "", // UID is not needed if there will be only one instance of the program 18 | Section: "kretprobe/mkdir", 19 | AttachToFuncName: "mkdir", 20 | EbpfFuncName: "kretpobe_mkdir", 21 | KProbeMaxActive: 100, 22 | }, 23 | }, 24 | PerfMaps: []*manager.PerfMap{ 25 | &manager.PerfMap{ 26 | Map: manager.Map{ 27 | Name: "my_constants", 28 | }, 29 | PerfMapOptions: manager.PerfMapOptions{ 30 | DataHandler: myDataHandler, 31 | }, 32 | }, 33 | }, 34 | } 35 | 36 | // myDataHandler - Perf event data handler 37 | func myDataHandler(cpu int, data []byte, perfmap *manager.PerfMap, manager *manager.Manager) { 38 | myConstant := ByteOrder.Uint64(data[0:8]) 39 | logrus.Printf("received: CPU:%d my_constant:%d", cpu, myConstant) 40 | } 41 | 42 | var editors = []manager.ConstantEditor{ 43 | { 44 | Name: "my_constant", 45 | Value: uint64(100), 46 | FailOnMissing: true, 47 | ProbeIdentificationPairs: []manager.ProbeIdentificationPair{ 48 | {"MyFirstHook", "kprobe_vfs_mkdir"}, 49 | }, 50 | }, 51 | { 52 | Name: "my_constant", 53 | Value: uint64(555), 54 | FailOnMissing: true, 55 | ProbeIdentificationPairs: []manager.ProbeIdentificationPair{ 56 | {"", "kprobe_vfs_rmdir"}, 57 | }, 58 | }, 59 | { 60 | Name: "unused_constant", 61 | Value: uint64(555), 62 | ProbeIdentificationPairs: []manager.ProbeIdentificationPair{}, 63 | }, 64 | } 65 | 66 | func main() { 67 | // Prepare manager options 68 | options := manager.Options{ConstantEditors: editors} 69 | 70 | // Initialize the manager 71 | if err := m.InitWithOptions(recoverAssets(), options); err != nil { 72 | logrus.Fatal(err) 73 | } 74 | 75 | // Start the manager 76 | if err := m.Start(); err != nil { 77 | logrus.Fatal(err) 78 | } 79 | logrus.Println("eBPF programs running, head over to /sys/kernel/debug/tracing/trace_pipe to see them in action.") 80 | 81 | // Demo 82 | logrus.Println("INITIAL PROGRAMS") 83 | if err := trigger(); err != nil { 84 | _ = m.Stop(manager.CleanAll) 85 | logrus.Fatal(err) 86 | } 87 | if err := demoClone(); err != nil { 88 | _ = m.Stop(manager.CleanAll) 89 | logrus.Fatal(err) 90 | } 91 | if err := demoAddHook(); err != nil { 92 | _ = m.Stop(manager.CleanAll) 93 | logrus.Fatal(err) 94 | } 95 | 96 | // Close the manager 97 | if err := m.Stop(manager.CleanAll); err != nil { 98 | logrus.Fatal(err) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /examples/clone_vs_add_hook/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "fmt" 7 | "io" 8 | "os" 9 | "time" 10 | "unsafe" 11 | 12 | "github.com/sirupsen/logrus" 13 | ) 14 | 15 | // ByteOrder - host byte order 16 | var ByteOrder binary.ByteOrder 17 | 18 | func init() { 19 | ByteOrder = getHostByteOrder() 20 | } 21 | 22 | // getHostByteOrder - Returns the host byte order 23 | func getHostByteOrder() binary.ByteOrder { 24 | var i int32 = 0x01020304 25 | u := unsafe.Pointer(&i) 26 | pb := (*byte)(u) 27 | b := *pb 28 | if b == 0x04 { 29 | return binary.LittleEndian 30 | } 31 | 32 | return binary.BigEndian 33 | } 34 | 35 | // recoverAssets - Recover ebpf asset 36 | func recoverAssets() io.ReaderAt { 37 | buf, err := Asset("/probe.o") 38 | if err != nil { 39 | logrus.Fatal(fmt.Errorf("error:%v, %s", err, "couldn't find asset")) 40 | } 41 | return bytes.NewReader(buf) 42 | } 43 | 44 | // trigger - Creates and then removes a tmp folder to trigger the probes 45 | func trigger() error { 46 | logrus.Println("Generating events to trigger the probes ...") 47 | // Creating a tmp directory to trigger the probes 48 | tmpDir := "/tmp/test_folder" 49 | logrus.Printf("creating %v", tmpDir) 50 | err := os.MkdirAll(tmpDir, 0666) 51 | if err != nil { 52 | return err 53 | } 54 | 55 | // Sleep a bit to give time to the perf event 56 | time.Sleep(500*time.Millisecond) 57 | 58 | // Removing a tmp directory to trigger the probes 59 | logrus.Printf("removing %v", tmpDir) 60 | err = os.RemoveAll(tmpDir) 61 | if err != nil { 62 | return err 63 | } 64 | 65 | // Sleep a bit to give time to the perf event 66 | time.Sleep(500*time.Millisecond) 67 | return nil 68 | } 69 | 70 | -------------------------------------------------------------------------------- /examples/instruction_patching/Makefile: -------------------------------------------------------------------------------- 1 | all: build-ebpf build run 2 | 3 | build-ebpf: 4 | mkdir -p ebpf/bin 5 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 6 | -Wno-unused-value \ 7 | -Wno-pointer-sign \ 8 | -Wno-compare-distinct-pointer-types \ 9 | -Wunused \ 10 | -Wall \ 11 | -Werror \ 12 | -I/lib/modules/$$(uname -r)/build/include \ 13 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 14 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 15 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 16 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 17 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 18 | -O2 -emit-llvm \ 19 | ebpf/main.c \ 20 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe.o 21 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg main -prefix "ebpf/bin" -o "probe.go" "ebpf/bin/probe.o" 22 | 23 | build: 24 | go build -o bin/main . 25 | 26 | run: 27 | sudo bin/main 28 | -------------------------------------------------------------------------------- /examples/instruction_patching/bin/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gojue/ebpfmanager/80670ed5a287e243e99c6ce5b44333221656201a/examples/instruction_patching/bin/.gitkeep -------------------------------------------------------------------------------- /examples/instruction_patching/ebpf/include/bpf_map.h: -------------------------------------------------------------------------------- 1 | #define BUF_SIZE_MAP_NS 256 2 | 3 | typedef struct bpf_map_def { 4 | unsigned int type; 5 | unsigned int key_size; 6 | unsigned int value_size; 7 | unsigned int max_entries; 8 | unsigned int map_flags; 9 | unsigned int inner_map_idx; 10 | unsigned int pinning; 11 | char namespace[BUF_SIZE_MAP_NS]; 12 | } bpf_map_def; 13 | 14 | enum bpf_pin_type { 15 | PIN_NONE = 0, 16 | PIN_OBJECT_NS, 17 | PIN_GLOBAL_NS, 18 | PIN_CUSTOM_NS, 19 | }; 20 | -------------------------------------------------------------------------------- /examples/instruction_patching/ebpf/main.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_map.h" 3 | #include "include/bpf_helpers.h" 4 | 5 | char _license[] SEC("license") = "GPL"; 6 | 7 | 8 | static void *(*bpf_patch)(unsigned long,...) = (void *)-1; 9 | 10 | SEC("kprobe/security_socket_create") 11 | int kprobe__security_socket_create(void *ctx) { 12 | int ret = 0; 13 | bpf_patch(ret); 14 | return 1; 15 | } -------------------------------------------------------------------------------- /examples/instruction_patching/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "embed" 5 | "fmt" 6 | "github.com/cilium/ebpf" 7 | "github.com/cilium/ebpf/asm" 8 | "github.com/sirupsen/logrus" 9 | "log" 10 | "time" 11 | 12 | manager "github.com/gojue/ebpfmanager" 13 | ) 14 | 15 | var Probe []byte 16 | 17 | const eBPFFuncName = "kprobe__security_socket_create" 18 | const eBPFAsmValue = 255 19 | 20 | var m1 = &manager.Manager{ 21 | Probes: []*manager.Probe{ 22 | { 23 | UID: "MyFirstHook", 24 | Section: "kprobe/vfs_mkdir", 25 | AttachToFuncName: "vfs_mkdir", 26 | EbpfFuncName: eBPFFuncName, 27 | }, 28 | }, 29 | InstructionPatchers: []manager.InstructionPatcherFunc{patchBPFTelemetry}, 30 | } 31 | 32 | const BPFTelemetryPatchCall = -1 33 | 34 | func getAllProgramSpecs(m *manager.Manager) ([]*ebpf.ProgramSpec, error) { 35 | var specs []*ebpf.ProgramSpec 36 | for _, p := range m.Probes { 37 | oldID := manager.ProbeIdentificationPair{p.UID, p.EbpfFuncName} 38 | s, present, err := m.GetProgramSpec(oldID) 39 | if err != nil { 40 | return nil, err 41 | } 42 | if !present { 43 | return nil, fmt.Errorf("could not find ProgramSpec for probe %v", oldID) 44 | } 45 | 46 | specs = append(specs, s...) 47 | } 48 | 49 | return specs, nil 50 | } 51 | 52 | func patchBPFTelemetry(m *manager.Manager) error { 53 | specs, err := getAllProgramSpecs(m) 54 | if err != nil { 55 | return err 56 | } 57 | for _, spec := range specs { 58 | if spec == nil { 59 | continue 60 | } 61 | iter := spec.Instructions.Iterate() 62 | for iter.Next() { 63 | ins := iter.Ins 64 | 65 | if !ins.IsBuiltinCall() { 66 | continue 67 | } 68 | 69 | if ins.Constant != BPFTelemetryPatchCall { 70 | continue 71 | } 72 | *ins = asm.Mov.Imm(asm.R1, int32(eBPFAsmValue)).WithMetadata(ins.Metadata) 73 | } 74 | } 75 | 76 | return nil 77 | } 78 | 79 | func main() { 80 | if err := run(); err != nil { 81 | log.Fatal(err) 82 | } 83 | } 84 | 85 | func run() error { 86 | if err := m1.Init(recoverAssets()); err != nil { 87 | return err 88 | } 89 | defer func() { 90 | if err := m1.Stop(manager.CleanAll); err != nil { 91 | log.Print(err) 92 | } 93 | }() 94 | 95 | if err := m1.Start(); err != nil { 96 | return err 97 | } 98 | 99 | log.Println("=> Use 'bpftool prog dump xlated id ' to verify that the instruction has been patched") 100 | log.Println("=> Enter to exit") 101 | // check output with `bpftool prog dump xlated id ` 102 | /* 103 | root@vm-ubuntu-arm64:/home/cfc4n# bpftool prog dump xlated id 664 104 | 0: (b7) r1 = 0 105 | 1: (b7) r1 = 255 106 | 2: (b7) r0 = 1 107 | 3: (95) exit 108 | */ 109 | // wait for eBPF program to be loaded 110 | time.Sleep(time.Second * 3) 111 | 112 | err := check(eBPFFuncName) 113 | 114 | if err != nil { 115 | logrus.Errorf("failed to check eBPF program: %v", err) 116 | } 117 | if err = m1.Stop(manager.CleanAll); err != nil { 118 | logrus.Fatal(err) 119 | } 120 | log.Println("=> Stopped the manager") 121 | return nil 122 | } 123 | -------------------------------------------------------------------------------- /examples/instruction_patching/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "fmt" 7 | "io" 8 | "os" 9 | "os/exec" 10 | "os/signal" 11 | "strings" 12 | "time" 13 | "unsafe" 14 | 15 | "github.com/sirupsen/logrus" 16 | ) 17 | 18 | // ByteOrder - host byte order 19 | var ByteOrder binary.ByteOrder 20 | 21 | const ( 22 | //BpfProgShowProgramId = "bpftool prog show name %s |grep %s |awk -F ':' '{print $1}'" 23 | BpfProgShowProgramId = "prog show name %s |grep %s |awk -F ':' '{print $1}'" 24 | BpfProgDumpXlatedId = "prog dump xlated id %s" 25 | BpfAsmCode = "r1 = %d" 26 | ) 27 | 28 | func init() { 29 | ByteOrder = getHostByteOrder() 30 | } 31 | 32 | // getHostByteOrder - Returns the host byte order 33 | func getHostByteOrder() binary.ByteOrder { 34 | var i int32 = 0x01020304 35 | u := unsafe.Pointer(&i) 36 | pb := (*byte)(u) 37 | b := *pb 38 | if b == 0x04 { 39 | return binary.LittleEndian 40 | } 41 | 42 | return binary.BigEndian 43 | } 44 | 45 | // recoverAssets - Recover ebpf asset 46 | func recoverAssets() io.ReaderAt { 47 | buf, err := Asset("/probe.o") 48 | if err != nil { 49 | logrus.Fatal(fmt.Errorf("error:%v, %s", err, "couldn't find asset")) 50 | } 51 | return bytes.NewReader(buf) 52 | } 53 | 54 | func check(progName string) error { 55 | if len(progName) >= 15 { 56 | progName = progName[:15] 57 | } 58 | var c = exec.Command("bpftool", "prog", "show", "name", progName) 59 | logrus.Println("executing command:", c.String()) 60 | output, err := c.Output() 61 | if err != nil { 62 | return fmt.Errorf("executing command:%s, error:%v", c.String(), err) 63 | } 64 | outputStr := string(output) 65 | var outArrs = strings.Split(outputStr, ":") 66 | if len(outArrs) < 2 { 67 | return fmt.Errorf("failed to find prog id in output:%s", outputStr) 68 | } 69 | var progId = outArrs[0] 70 | logrus.Println("output:", progId) 71 | c = exec.Command("bpftool", "prog", "dump", "xlated", "id", progId) 72 | logrus.Println("executing command:", c.String()) 73 | output, err = c.Output() 74 | if err != nil { 75 | return fmt.Errorf("executing command:%s, error:%v", c.String(), err) 76 | } 77 | outputStr = string(output) 78 | logrus.Printf("output:%s", outputStr) 79 | var asmCode = fmt.Sprintf(BpfAsmCode, eBPFAsmValue) 80 | if !strings.Contains(outputStr, asmCode) { 81 | logrus.Fatalf("failed to find asm code:%s in output:%s", asmCode, outputStr) 82 | } 83 | logrus.Println("found asm code:", asmCode) 84 | return nil 85 | } 86 | 87 | func wait() { 88 | logrus.Println("run next testcase after 3 second") 89 | time.Sleep(time.Second * 3) 90 | //return 91 | sig := make(chan os.Signal, 1) 92 | signal.Notify(sig, os.Interrupt, os.Kill) 93 | <-sig 94 | fmt.Println() 95 | } 96 | -------------------------------------------------------------------------------- /examples/link_pinning/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | ebpf/bin/ 3 | -------------------------------------------------------------------------------- /examples/link_pinning/Makefile: -------------------------------------------------------------------------------- 1 | all: build-ebpf build run 2 | 3 | build-ebpf: 4 | mkdir -p ebpf/bin 5 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 6 | -Wno-unused-value \ 7 | -Wno-pointer-sign \ 8 | -Wno-compare-distinct-pointer-types \ 9 | -Wunused \ 10 | -Wall \ 11 | -Werror \ 12 | -I/lib/modules/$$(uname -r)/build/include \ 13 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 14 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 15 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 16 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 17 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 18 | -O2 -emit-llvm \ 19 | ebpf/main.c \ 20 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe.o 21 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg main -prefix "ebpf/bin" -o "probe.go" "ebpf/bin/probe.o" 22 | 23 | build: 24 | go build -o bin/main . 25 | 26 | run: 27 | sudo bin/main 28 | -------------------------------------------------------------------------------- /examples/link_pinning/ebpf/include/bpf_helpers.h: -------------------------------------------------------------------------------- 1 | #ifndef __BPF_HELPERS_H 2 | #define __BPF_HELPERS_H 3 | 4 | #define bpf_printk(fmt, ...) \ 5 | ({ \ 6 | char ____fmt[] = fmt; \ 7 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 8 | ##__VA_ARGS__); \ 9 | }) 10 | 11 | /* helper macro to place programs, maps, license in 12 | * different sections in elf_bpf file. Section names 13 | * are interpreted by elf_bpf loader 14 | */ 15 | #define SEC(NAME) __attribute__((section(NAME), used)) 16 | 17 | /* helper functions called from eBPF programs written in C */ 18 | static void *(*bpf_map_lookup_elem)(void *map, void *key) = 19 | (void *)BPF_FUNC_map_lookup_elem; 20 | static int (*bpf_map_update_elem)(void *map, void *key, void *value, 21 | unsigned long long flags) = 22 | (void *)BPF_FUNC_map_update_elem; 23 | static int (*bpf_map_delete_elem)(void *map, void *key) = 24 | (void *)BPF_FUNC_map_delete_elem; 25 | static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) = 26 | (void *)BPF_FUNC_probe_read; 27 | static unsigned long long (*bpf_ktime_get_ns)(void) = 28 | (void *)BPF_FUNC_ktime_get_ns; 29 | static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = 30 | (void *)BPF_FUNC_trace_printk; 31 | static unsigned long long (*bpf_get_smp_processor_id)(void) = 32 | (void *)BPF_FUNC_get_smp_processor_id; 33 | static unsigned long long (*bpf_get_current_pid_tgid)(void) = 34 | (void *)BPF_FUNC_get_current_pid_tgid; 35 | static unsigned long long (*bpf_get_current_uid_gid)(void) = 36 | (void *)BPF_FUNC_get_current_uid_gid; 37 | static int (*bpf_get_current_comm)(void *buf, int buf_size) = 38 | (void *)BPF_FUNC_get_current_comm; 39 | static int (*bpf_perf_event_read)(void *map, int index) = 40 | (void *)BPF_FUNC_perf_event_read; 41 | static int (*bpf_clone_redirect)(void *ctx, int ifindex, int flags) = 42 | (void *)BPF_FUNC_clone_redirect; 43 | static int (*bpf_redirect)(int ifindex, int flags) = 44 | (void *)BPF_FUNC_redirect; 45 | static int (*bpf_perf_event_output)(void *ctx, void *map, 46 | unsigned long long flags, void *data, 47 | int size) = 48 | (void *)BPF_FUNC_perf_event_output; 49 | static int (*bpf_skb_get_tunnel_key)(void *ctx, void *key, int size, int flags) = 50 | (void *)BPF_FUNC_skb_get_tunnel_key; 51 | static int (*bpf_skb_set_tunnel_key)(void *ctx, void *key, int size, int flags) = 52 | (void *)BPF_FUNC_skb_set_tunnel_key; 53 | static unsigned long long (*bpf_get_prandom_u32)(void) = 54 | (void *)BPF_FUNC_get_prandom_u32; 55 | 56 | /* llvm builtin functions that eBPF C program may use to 57 | * emit BPF_LD_ABS and BPF_LD_IND instructions 58 | */ 59 | struct sk_buff; 60 | unsigned long long load_byte(void *skb, 61 | unsigned long long off) asm("llvm.bpf.load.byte"); 62 | unsigned long long load_half(void *skb, 63 | unsigned long long off) asm("llvm.bpf.load.half"); 64 | unsigned long long load_word(void *skb, 65 | unsigned long long off) asm("llvm.bpf.load.word"); 66 | 67 | /* a helper structure used by eBPF C program 68 | * to describe map attributes to elf_bpf loader 69 | */ 70 | #define BUF_SIZE_MAP_NS 256 71 | 72 | // struct bpf_map_def 73 | // { 74 | // unsigned int type; 75 | // unsigned int key_size; 76 | // unsigned int value_size; 77 | // unsigned int max_entries; 78 | // unsigned int map_flags; 79 | // unsigned int pinning; 80 | // char namespace[BUF_SIZE_MAP_NS]; 81 | // }; 82 | 83 | static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = 84 | (void *)BPF_FUNC_skb_store_bytes; 85 | static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) = 86 | (void *)BPF_FUNC_l3_csum_replace; 87 | static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) = 88 | (void *)BPF_FUNC_l4_csum_replace; 89 | 90 | #if defined(__x86_64__) 91 | 92 | #define PT_REGS_PARM1(x) ((x)->di) 93 | #define PT_REGS_PARM2(x) ((x)->si) 94 | #define PT_REGS_PARM3(x) ((x)->dx) 95 | #define PT_REGS_PARM4(x) ((x)->cx) 96 | #define PT_REGS_PARM5(x) ((x)->r8) 97 | #define PT_REGS_RET(x) ((x)->sp) 98 | #define PT_REGS_FP(x) ((x)->bp) 99 | #define PT_REGS_RC(x) ((x)->ax) 100 | #define PT_REGS_SP(x) ((x)->sp) 101 | #define PT_REGS_IP(x) ((x)->ip) 102 | 103 | #elif defined(__s390x__) 104 | 105 | #define PT_REGS_PARM1(x) ((x)->gprs[2]) 106 | #define PT_REGS_PARM2(x) ((x)->gprs[3]) 107 | #define PT_REGS_PARM3(x) ((x)->gprs[4]) 108 | #define PT_REGS_PARM4(x) ((x)->gprs[5]) 109 | #define PT_REGS_PARM5(x) ((x)->gprs[6]) 110 | #define PT_REGS_RET(x) ((x)->gprs[14]) 111 | #define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */ 112 | #define PT_REGS_RC(x) ((x)->gprs[2]) 113 | #define PT_REGS_SP(x) ((x)->gprs[15]) 114 | #define PT_REGS_IP(x) ((x)->ip) 115 | 116 | #elif defined(__aarch64__) 117 | 118 | #define PT_REGS_PARM1(x) ((x)->regs[0]) 119 | #define PT_REGS_PARM2(x) ((x)->regs[1]) 120 | #define PT_REGS_PARM3(x) ((x)->regs[2]) 121 | #define PT_REGS_PARM4(x) ((x)->regs[3]) 122 | #define PT_REGS_PARM5(x) ((x)->regs[4]) 123 | #define PT_REGS_RET(x) ((x)->regs[30]) 124 | #define PT_REGS_FP(x) ((x)->regs[29]) /* Works only with CONFIG_FRAME_POINTER */ 125 | #define PT_REGS_RC(x) ((x)->regs[0]) 126 | #define PT_REGS_SP(x) ((x)->sp) 127 | #define PT_REGS_IP(x) ((x)->pc) 128 | 129 | #elif defined(__powerpc__) 130 | 131 | #define PT_REGS_PARM1(x) ((x)->gpr[3]) 132 | #define PT_REGS_PARM2(x) ((x)->gpr[4]) 133 | #define PT_REGS_PARM3(x) ((x)->gpr[5]) 134 | #define PT_REGS_PARM4(x) ((x)->gpr[6]) 135 | #define PT_REGS_PARM5(x) ((x)->gpr[7]) 136 | #define PT_REGS_RC(x) ((x)->gpr[3]) 137 | #define PT_REGS_SP(x) ((x)->sp) 138 | #define PT_REGS_IP(x) ((x)->nip) 139 | 140 | #endif 141 | 142 | #ifdef __powerpc__ 143 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) 144 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP 145 | #else 146 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) 147 | #define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), \ 148 | (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) 149 | #endif 150 | 151 | #endif 152 | -------------------------------------------------------------------------------- /examples/link_pinning/ebpf/main.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_helpers.h" 3 | 4 | SEC("raw_tracepoint/sys_enter") 5 | int raw_tracepoint_sys_enter(void *ctx) 6 | { 7 | bpf_printk("sys_enter enter (tracepoint)\n"); 8 | return 0; 9 | }; 10 | 11 | char _license[] SEC("license") = "GPL"; 12 | __u32 _version SEC("version") = 0xFFFFFFFE; 13 | -------------------------------------------------------------------------------- /examples/link_pinning/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "github.com/sirupsen/logrus" 6 | 7 | manager "github.com/gojue/ebpfmanager" 8 | ) 9 | 10 | var m = &manager.Manager{ 11 | Probes: []*manager.Probe{ 12 | { 13 | Section: "raw_tracepoint/sys_enter", 14 | EbpfFuncName: "raw_tracepoint_sys_enter", 15 | LinkPinPath: "/sys/fs/bpf/sys_enter_link", 16 | }, 17 | }, 18 | } 19 | 20 | func main() { 21 | // Parse CLI arguments 22 | var kill bool 23 | flag.BoolVar(&kill, "kill", false, "kills the programs suddenly before doing any cleanup") 24 | flag.Parse() 25 | 26 | logrus.Println("if User-Space application exits, pinned link programs will still run") 27 | 28 | // Initialize the manager 29 | if err := m.Init(recoverAssets()); err != nil { 30 | logrus.Fatal(err) 31 | } 32 | 33 | // Start the manager 34 | if err := m.Start(); err != nil { 35 | logrus.Fatal(err) 36 | } 37 | 38 | logrus.Println("successfully started, head over to /sys/kernel/debug/tracing/trace_pipe") 39 | 40 | // Create a folder to trigger the probes 41 | if err := trigger(); err != nil { 42 | logrus.Error(err) 43 | } 44 | 45 | if kill { 46 | logrus.Println("=> Stopping the program without cleanup, the pinned link should show up in /sys/fs/bpf/") 47 | logrus.Println("=> You can check the logs /sys/kernel/debug/tracing/trace_pipe") 48 | return 49 | } 50 | 51 | // Close the manager 52 | if err := m.Stop(manager.CleanAll); err != nil { 53 | logrus.Fatal(err) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /examples/link_pinning/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "os/exec" 8 | 9 | "errors" 10 | 11 | "github.com/sirupsen/logrus" 12 | ) 13 | 14 | // recoverAssets - Recover ebpf asset 15 | func recoverAssets() io.ReaderAt { 16 | buf, err := Asset("/probe.o") 17 | if err != nil { 18 | logrus.Fatal(errors.New(fmt.Sprintf("error:%v , couldn't find asset", err))) 19 | } 20 | return bytes.NewReader(buf) 21 | } 22 | 23 | // trigger - execute whoami to trigger the probes 24 | func trigger() error { 25 | logrus.Println("Generating events to trigger the probes ...") 26 | // Run whoami to trigger the event 27 | cmd := exec.Command("/usr/bin/whoami") 28 | return cmd.Run() 29 | } 30 | -------------------------------------------------------------------------------- /examples/map_rewrite_vs_map_router/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | ebpf/bin/ 3 | -------------------------------------------------------------------------------- /examples/map_rewrite_vs_map_router/Makefile: -------------------------------------------------------------------------------- 1 | all: build-ebpf build run 2 | 3 | build-ebpf: build-prog1 build-prog2 4 | 5 | build-prog1: 6 | mkdir -p ebpf/bin 7 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 8 | -Wno-unused-value \ 9 | -Wno-pointer-sign \ 10 | -Wno-compare-distinct-pointer-types \ 11 | -Wunused \ 12 | -Wall \ 13 | -Werror \ 14 | -I/lib/modules/$$(uname -r)/build/include \ 15 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 16 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 17 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 18 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 19 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 20 | -O2 -emit-llvm \ 21 | ebpf/prog1.c \ 22 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/prog1.o 23 | 24 | build-prog2: 25 | mkdir -p ebpf/bin 26 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 27 | -Wno-unused-value \ 28 | -Wno-pointer-sign \ 29 | -Wno-compare-distinct-pointer-types \ 30 | -Wunused \ 31 | -Wall \ 32 | -Werror \ 33 | -I/lib/modules/$$(uname -r)/build/include \ 34 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 35 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 36 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 37 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 38 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 39 | -O2 -emit-llvm \ 40 | ebpf/prog2.c \ 41 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/prog2.o 42 | 43 | build: 44 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg main -prefix "ebpf/bin" -o "probe.go" "ebpf/bin/prog1.o" "ebpf/bin/prog2.o" 45 | go build -o bin/main . 46 | 47 | run: 48 | sudo bin/main 49 | -------------------------------------------------------------------------------- /examples/map_rewrite_vs_map_router/demo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/sirupsen/logrus" 6 | 7 | "github.com/cilium/ebpf" 8 | "github.com/gojue/ebpfmanager" 9 | ) 10 | 11 | func demoMapEditor() error { 12 | logrus.Println("MAP EDITOR DEMO") 13 | // Select the shared map to give it to m2 14 | sharedCache1, found, err := m1.GetMap("shared_cache1") 15 | if err != nil || !found { 16 | return fmt.Errorf("error:%v, %s", err, "couldn't find shared_cache1 in m1") 17 | } 18 | if err = dumpSharedMap(sharedCache1); err != nil { 19 | return err 20 | } 21 | 22 | // Give shared_cache1 to m2 through a map editor 23 | options := manager.Options{MapEditors: map[string]*ebpf.Map{ 24 | "shared_cache1": sharedCache1, 25 | }, 26 | MapSpecEditors: map[string]manager.MapSpecEditor{ 27 | "maps_router": { 28 | InnerMap: &ebpf.MapSpec{ 29 | Name: "routed_cache", 30 | Type: ebpf.Hash, 31 | KeySize: 4, 32 | ValueSize: 4, 33 | MaxEntries: 10, 34 | Flags: 0, 35 | }, 36 | EditorFlag: manager.EditInnerMap, 37 | }, 38 | }, 39 | } 40 | // Initialize m2, edit shared_cache1 and start it 41 | if err = m2.InitWithOptions(recoverAsset("/prog2.o"), options); err != nil { 42 | return err 43 | } 44 | if err = m2.Start(); err != nil { 45 | return err 46 | } 47 | if err = trigger(); err != nil { 48 | return err 49 | } 50 | return dumpSharedMap(sharedCache1) 51 | } 52 | 53 | func demoMapRouter() error { 54 | logrus.Println("MAP ROUTER DEMO") 55 | // Select the shared map to give it to m2 56 | sharedCache2, found, err := m1.GetMap("shared_cache2") 57 | if err != nil || !found { 58 | return fmt.Errorf("error :%v, %s", err, "couldn't find shared_cache2 in m1") 59 | } 60 | if err = dumpSharedMap(sharedCache2); err != nil { 61 | return err 62 | } 63 | 64 | // Give shared_cache2 to m2 through a map router 65 | router := manager.MapRoute{RoutingMapName: "maps_router", Key: uint32(1), Map: sharedCache2} 66 | if err := m2.UpdateMapRoutes(router); err != nil { 67 | return err 68 | } 69 | 70 | if err = trigger(); err != nil { 71 | return err 72 | } 73 | return dumpSharedMap(sharedCache2) 74 | } 75 | -------------------------------------------------------------------------------- /examples/map_rewrite_vs_map_router/ebpf/include/bpf_map.h: -------------------------------------------------------------------------------- 1 | #define BUF_SIZE_MAP_NS 256 2 | 3 | typedef struct bpf_map_def { 4 | unsigned int type; 5 | unsigned int key_size; 6 | unsigned int value_size; 7 | unsigned int max_entries; 8 | unsigned int map_flags; 9 | unsigned int inner_map_idx; 10 | unsigned int pinning; 11 | char namespace[BUF_SIZE_MAP_NS]; 12 | } bpf_map_def; 13 | 14 | enum bpf_pin_type { 15 | PIN_NONE = 0, 16 | PIN_OBJECT_NS, 17 | PIN_GLOBAL_NS, 18 | PIN_CUSTOM_NS, 19 | }; 20 | -------------------------------------------------------------------------------- /examples/map_rewrite_vs_map_router/ebpf/prog1.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_map.h" 3 | #include "include/bpf_helpers.h" 4 | 5 | // shared_cache - This map will be shared with other Manager 6 | struct bpf_map_def SEC("maps/shared_cache1") shared_cache1 = { 7 | .type = BPF_MAP_TYPE_HASH, 8 | .key_size = sizeof(u32), 9 | .value_size = sizeof(u32), 10 | .max_entries = 10, 11 | }; 12 | 13 | // shared_cache2 - This map will be shared with other Manager 14 | struct bpf_map_def SEC("maps/shared_cache2") shared_cache2 = { 15 | .type = BPF_MAP_TYPE_HASH, 16 | .key_size = sizeof(u32), 17 | .value_size = sizeof(u32), 18 | .max_entries = 10, 19 | }; 20 | 21 | SEC("kretprobe/vfs_mkdir") 22 | int kretprobe_vfs_mkdir(void *ctx) 23 | { 24 | // retrieve the value saved in the cache at key 1 25 | u32 key = 1; 26 | u32 *value = bpf_map_lookup_elem(&shared_cache1, &key); 27 | if (!value) { 28 | bpf_printk("(prog1) shared_cache1 is empty\n"); 29 | } else { 30 | bpf_printk("(prog1) shared_cache1 contains %u\n", *value); 31 | } 32 | 33 | value = bpf_map_lookup_elem(&shared_cache2, &key); 34 | if (!value) { 35 | bpf_printk("(prog1) shared_cache2 is empty\n"); 36 | } else { 37 | bpf_printk("(prog1) shared_cache2 contains %u\n", *value); 38 | } 39 | return 0; 40 | }; 41 | 42 | char _license[] SEC("license") = "GPL"; 43 | __u32 _version SEC("version") = 0xFFFFFFFE; 44 | -------------------------------------------------------------------------------- /examples/map_rewrite_vs_map_router/ebpf/prog2.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_map.h" 3 | #include "include/bpf_helpers.h" 4 | 5 | // shared_cache - This map will be shared with other Manager 6 | struct bpf_map_def SEC("maps/shared_cache1") shared_cache1 = { 7 | .type = BPF_MAP_TYPE_HASH, 8 | .key_size = sizeof(u32), 9 | .value_size = sizeof(u32), 10 | .max_entries = 10, 11 | }; 12 | 13 | /** 14 | * routed_cache is used to define the types of maps that are expected in maps_router 15 | * WARNING: it has to be the first map defined in the `maps/maps_router` 16 | * section since it is referred to as map #0 in maps_router. 17 | */ 18 | struct bpf_map_def SEC("maps/maps_router") routed_cache = { 19 | .type = BPF_MAP_TYPE_HASH, 20 | .key_size = sizeof(u32), 21 | .value_size = sizeof(u32), 22 | .max_entries = 10, 23 | }; 24 | 25 | struct bpf_map_def SEC("maps/maps_router") maps_router = { 26 | .type = BPF_MAP_TYPE_HASH_OF_MAPS, 27 | .key_size = sizeof(u32), 28 | .max_entries = 10, 29 | .inner_map_idx = 0, /* map_fd[0] is routed_cache */ 30 | }; 31 | 32 | SEC("kprobe/vfs_mkdir") 33 | int kprobe_vfs_mkdir(void *ctx) 34 | { 35 | bpf_printk("(prog2) writing 42 in shared_cache1 at key 1 ...\n"); 36 | // Update the shared cache 37 | u32 key = 1; 38 | u32 val = 42; 39 | bpf_map_update_elem(&shared_cache1, &key, &val, BPF_ANY); 40 | 41 | // Update the routed map 42 | val = 500; 43 | void *routed_map = bpf_map_lookup_elem(&maps_router, &key); 44 | if (routed_map == NULL) 45 | { 46 | return 0; 47 | } 48 | bpf_printk("(prog2) writing 500 in router_map at key 1 ...\n"); 49 | bpf_map_update_elem(routed_map, &key, &val, BPF_ANY); 50 | return 0; 51 | }; 52 | 53 | char _license[] SEC("license") = "GPL"; 54 | __u32 _version SEC("version") = 0xFFFFFFFE; 55 | -------------------------------------------------------------------------------- /examples/map_rewrite_vs_map_router/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/gojue/ebpfmanager" 5 | "github.com/sirupsen/logrus" 6 | ) 7 | 8 | var m1 = &manager.Manager{ 9 | Probes: []*manager.Probe{ 10 | { 11 | Section: "kretprobe/vfs_mkdir", 12 | EbpfFuncName: "kretprobe_vfs_mkdir", 13 | AttachToFuncName: "vfs_mkdir", 14 | }, 15 | }, 16 | } 17 | 18 | var m2 = &manager.Manager{ 19 | Probes: []*manager.Probe{ 20 | { 21 | Section: "kprobe/vfs_mkdir", 22 | EbpfFuncName: "kprobe_vfs_mkdir", 23 | AttachToFuncName: "vfs_mkdir", 24 | }, 25 | }, 26 | } 27 | 28 | func main() { 29 | // Initialize & start m1 30 | if err := m1.Init(recoverAsset("/prog1.o")); err != nil { 31 | logrus.Fatal(err) 32 | } 33 | if err := m1.Start(); err != nil { 34 | logrus.Fatal(err) 35 | } 36 | logrus.Println("Head over to /sys/kernel/debug/tracing/trace_pipe to see the eBPF programs in action") 37 | 38 | // Start demos 39 | if err := demoMapEditor(); err != nil { 40 | logrus.Fatal(err) 41 | cleanup() 42 | } 43 | if err := demoMapRouter(); err != nil { 44 | logrus.Fatal(err) 45 | cleanup() 46 | } 47 | 48 | // Close the managers 49 | if err := m1.Stop(manager.CleanAll); err != nil { 50 | logrus.Fatal(err) 51 | } 52 | if err := m2.Stop(manager.CleanInternal); err != nil { 53 | logrus.Fatal(err) 54 | } 55 | } 56 | 57 | func cleanup() { 58 | _ = m1.Stop(manager.CleanAll) 59 | _ = m2.Stop(manager.CleanInternal) 60 | } 61 | -------------------------------------------------------------------------------- /examples/map_rewrite_vs_map_router/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "fmt" 7 | "github.com/cilium/ebpf" 8 | "io" 9 | "os" 10 | "unsafe" 11 | 12 | "github.com/sirupsen/logrus" 13 | ) 14 | 15 | // ByteOrder - host byte order 16 | var ByteOrder binary.ByteOrder 17 | 18 | func init() { 19 | ByteOrder = getHostByteOrder() 20 | } 21 | 22 | // getHostByteOrder - Returns the host byte order 23 | func getHostByteOrder() binary.ByteOrder { 24 | var i int32 = 0x01020304 25 | u := unsafe.Pointer(&i) 26 | pb := (*byte)(u) 27 | b := *pb 28 | if b == 0x04 { 29 | return binary.LittleEndian 30 | } 31 | 32 | return binary.BigEndian 33 | } 34 | 35 | // recoverAsset - Recover ebpf asset 36 | func recoverAsset(asset string) io.ReaderAt { 37 | buf, err := Asset(asset) 38 | if err != nil { 39 | logrus.Fatal(fmt.Errorf("error:%v, %s", err, "couldn't find asset")) 40 | } 41 | return bytes.NewReader(buf) 42 | } 43 | 44 | // trigger - Creates and then removes a tmp folder to trigger the probes 45 | func trigger() error { 46 | logrus.Println("Generating events to trigger the probes ...") 47 | 48 | // Creating a tmp directory to trigger the probes 49 | tmpDir := "/tmp/test_folder" 50 | logrus.Printf("creating %v", tmpDir) 51 | err := os.MkdirAll(tmpDir, 0666) 52 | if err != nil { 53 | return err 54 | } 55 | 56 | // Removing the tmp directory 57 | return os.RemoveAll(tmpDir) 58 | } 59 | 60 | // dumpSharedMap - Dumps the content of the provided map at the provided key 61 | func dumpSharedMap(sharedMap *ebpf.Map) error { 62 | var key, val uint32 63 | entries := sharedMap.Iterate() 64 | for entries.Next(&key, &val) { 65 | // Order of keys is non-deterministic due to randomized map seed 66 | logrus.Printf("%v contains %v at key %v", sharedMap, val, key) 67 | } 68 | return entries.Err() 69 | } 70 | -------------------------------------------------------------------------------- /examples/mapspec_editor/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | ebpf/bin/ 3 | -------------------------------------------------------------------------------- /examples/mapspec_editor/Makefile: -------------------------------------------------------------------------------- 1 | all: build-ebpf build run 2 | 3 | build-ebpf: 4 | mkdir -p ebpf/bin 5 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 6 | -Wno-unused-value \ 7 | -Wno-pointer-sign \ 8 | -Wno-compare-distinct-pointer-types \ 9 | -Wunused \ 10 | -Wall \ 11 | -Werror \ 12 | -I/lib/modules/$$(uname -r)/build/include \ 13 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 14 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 15 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 16 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 17 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 18 | -O2 -emit-llvm \ 19 | ebpf/main.c \ 20 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe.o 21 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg main -prefix "ebpf/bin" -o "probe.go" "ebpf/bin/probe.o" 22 | 23 | build: 24 | go build -o bin/main . 25 | 26 | run: 27 | sudo bin/main 28 | -------------------------------------------------------------------------------- /examples/mapspec_editor/ebpf/include/bpf_helpers.h: -------------------------------------------------------------------------------- 1 | #ifndef __BPF_HELPERS_H 2 | #define __BPF_HELPERS_H 3 | 4 | #define bpf_printk(fmt, ...) \ 5 | ({ \ 6 | char ____fmt[] = fmt; \ 7 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 8 | ##__VA_ARGS__); \ 9 | }) 10 | 11 | /* helper macro to place programs, maps, license in 12 | * different sections in elf_bpf file. Section names 13 | * are interpreted by elf_bpf loader 14 | */ 15 | #define SEC(NAME) __attribute__((section(NAME), used)) 16 | 17 | /* helper functions called from eBPF programs written in C */ 18 | static void *(*bpf_map_lookup_elem)(void *map, void *key) = 19 | (void *)BPF_FUNC_map_lookup_elem; 20 | static int (*bpf_map_update_elem)(void *map, void *key, void *value, 21 | unsigned long long flags) = 22 | (void *)BPF_FUNC_map_update_elem; 23 | static int (*bpf_map_delete_elem)(void *map, void *key) = 24 | (void *)BPF_FUNC_map_delete_elem; 25 | static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) = 26 | (void *)BPF_FUNC_probe_read; 27 | static unsigned long long (*bpf_ktime_get_ns)(void) = 28 | (void *)BPF_FUNC_ktime_get_ns; 29 | static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = 30 | (void *)BPF_FUNC_trace_printk; 31 | static unsigned long long (*bpf_get_smp_processor_id)(void) = 32 | (void *)BPF_FUNC_get_smp_processor_id; 33 | static unsigned long long (*bpf_get_current_pid_tgid)(void) = 34 | (void *)BPF_FUNC_get_current_pid_tgid; 35 | static unsigned long long (*bpf_get_current_uid_gid)(void) = 36 | (void *)BPF_FUNC_get_current_uid_gid; 37 | static int (*bpf_get_current_comm)(void *buf, int buf_size) = 38 | (void *)BPF_FUNC_get_current_comm; 39 | static int (*bpf_perf_event_read)(void *map, int index) = 40 | (void *)BPF_FUNC_perf_event_read; 41 | static int (*bpf_clone_redirect)(void *ctx, int ifindex, int flags) = 42 | (void *)BPF_FUNC_clone_redirect; 43 | static int (*bpf_redirect)(int ifindex, int flags) = 44 | (void *)BPF_FUNC_redirect; 45 | static int (*bpf_perf_event_output)(void *ctx, void *map, 46 | unsigned long long flags, void *data, 47 | int size) = 48 | (void *)BPF_FUNC_perf_event_output; 49 | static int (*bpf_skb_get_tunnel_key)(void *ctx, void *key, int size, int flags) = 50 | (void *)BPF_FUNC_skb_get_tunnel_key; 51 | static int (*bpf_skb_set_tunnel_key)(void *ctx, void *key, int size, int flags) = 52 | (void *)BPF_FUNC_skb_set_tunnel_key; 53 | static unsigned long long (*bpf_get_prandom_u32)(void) = 54 | (void *)BPF_FUNC_get_prandom_u32; 55 | 56 | /* llvm builtin functions that eBPF C program may use to 57 | * emit BPF_LD_ABS and BPF_LD_IND instructions 58 | */ 59 | struct sk_buff; 60 | unsigned long long load_byte(void *skb, 61 | unsigned long long off) asm("llvm.bpf.load.byte"); 62 | unsigned long long load_half(void *skb, 63 | unsigned long long off) asm("llvm.bpf.load.half"); 64 | unsigned long long load_word(void *skb, 65 | unsigned long long off) asm("llvm.bpf.load.word"); 66 | 67 | /* a helper structure used by eBPF C program 68 | * to describe map attributes to elf_bpf loader 69 | */ 70 | #define BUF_SIZE_MAP_NS 256 71 | 72 | // struct bpf_map_def 73 | // { 74 | // unsigned int type; 75 | // unsigned int key_size; 76 | // unsigned int value_size; 77 | // unsigned int max_entries; 78 | // unsigned int map_flags; 79 | // unsigned int pinning; 80 | // char namespace[BUF_SIZE_MAP_NS]; 81 | // }; 82 | 83 | static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = 84 | (void *)BPF_FUNC_skb_store_bytes; 85 | static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) = 86 | (void *)BPF_FUNC_l3_csum_replace; 87 | static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) = 88 | (void *)BPF_FUNC_l4_csum_replace; 89 | 90 | #if defined(__x86_64__) 91 | 92 | #define PT_REGS_PARM1(x) ((x)->di) 93 | #define PT_REGS_PARM2(x) ((x)->si) 94 | #define PT_REGS_PARM3(x) ((x)->dx) 95 | #define PT_REGS_PARM4(x) ((x)->cx) 96 | #define PT_REGS_PARM5(x) ((x)->r8) 97 | #define PT_REGS_RET(x) ((x)->sp) 98 | #define PT_REGS_FP(x) ((x)->bp) 99 | #define PT_REGS_RC(x) ((x)->ax) 100 | #define PT_REGS_SP(x) ((x)->sp) 101 | #define PT_REGS_IP(x) ((x)->ip) 102 | 103 | #elif defined(__s390x__) 104 | 105 | #define PT_REGS_PARM1(x) ((x)->gprs[2]) 106 | #define PT_REGS_PARM2(x) ((x)->gprs[3]) 107 | #define PT_REGS_PARM3(x) ((x)->gprs[4]) 108 | #define PT_REGS_PARM4(x) ((x)->gprs[5]) 109 | #define PT_REGS_PARM5(x) ((x)->gprs[6]) 110 | #define PT_REGS_RET(x) ((x)->gprs[14]) 111 | #define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */ 112 | #define PT_REGS_RC(x) ((x)->gprs[2]) 113 | #define PT_REGS_SP(x) ((x)->gprs[15]) 114 | #define PT_REGS_IP(x) ((x)->ip) 115 | 116 | #elif defined(__aarch64__) 117 | 118 | #define PT_REGS_PARM1(x) ((x)->regs[0]) 119 | #define PT_REGS_PARM2(x) ((x)->regs[1]) 120 | #define PT_REGS_PARM3(x) ((x)->regs[2]) 121 | #define PT_REGS_PARM4(x) ((x)->regs[3]) 122 | #define PT_REGS_PARM5(x) ((x)->regs[4]) 123 | #define PT_REGS_RET(x) ((x)->regs[30]) 124 | #define PT_REGS_FP(x) ((x)->regs[29]) /* Works only with CONFIG_FRAME_POINTER */ 125 | #define PT_REGS_RC(x) ((x)->regs[0]) 126 | #define PT_REGS_SP(x) ((x)->sp) 127 | #define PT_REGS_IP(x) ((x)->pc) 128 | 129 | #elif defined(__powerpc__) 130 | 131 | #define PT_REGS_PARM1(x) ((x)->gpr[3]) 132 | #define PT_REGS_PARM2(x) ((x)->gpr[4]) 133 | #define PT_REGS_PARM3(x) ((x)->gpr[5]) 134 | #define PT_REGS_PARM4(x) ((x)->gpr[6]) 135 | #define PT_REGS_PARM5(x) ((x)->gpr[7]) 136 | #define PT_REGS_RC(x) ((x)->gpr[3]) 137 | #define PT_REGS_SP(x) ((x)->sp) 138 | #define PT_REGS_IP(x) ((x)->nip) 139 | 140 | #endif 141 | 142 | #ifdef __powerpc__ 143 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) 144 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP 145 | #else 146 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) 147 | #define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), \ 148 | (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) 149 | #endif 150 | 151 | #endif 152 | -------------------------------------------------------------------------------- /examples/mapspec_editor/ebpf/include/bpf_map.h: -------------------------------------------------------------------------------- 1 | #define BUF_SIZE_MAP_NS 256 2 | 3 | typedef struct bpf_map_def { 4 | unsigned int type; 5 | unsigned int key_size; 6 | unsigned int value_size; 7 | unsigned int max_entries; 8 | unsigned int map_flags; 9 | unsigned int inner_map_idx; 10 | unsigned int pinning; 11 | char namespace[BUF_SIZE_MAP_NS]; 12 | } bpf_map_def; 13 | 14 | enum bpf_pin_type { 15 | PIN_NONE = 0, 16 | PIN_OBJECT_NS, 17 | PIN_GLOBAL_NS, 18 | PIN_CUSTOM_NS, 19 | }; 20 | -------------------------------------------------------------------------------- /examples/mapspec_editor/ebpf/main.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_map.h" 3 | #include "include/bpf_helpers.h" 4 | 5 | struct bpf_map_def SEC("maps/cache") cache = { 6 | .type = BPF_MAP_TYPE_HASH, 7 | .key_size = sizeof(u32), 8 | .value_size = sizeof(u32), 9 | .max_entries = 10, 10 | }; 11 | 12 | char _license[] SEC("license") = "GPL"; 13 | __u32 _version SEC("version") = 0xFFFFFFFE; 14 | -------------------------------------------------------------------------------- /examples/mapspec_editor/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/cilium/ebpf" 5 | "github.com/gojue/ebpfmanager" 6 | "github.com/sirupsen/logrus" 7 | "golang.org/x/sys/unix" 8 | "math" 9 | ) 10 | 11 | var m = &manager.Manager{} 12 | 13 | func main() { 14 | options := manager.Options{ 15 | MapSpecEditors: map[string]manager.MapSpecEditor{ 16 | "cache": { 17 | Type: ebpf.LRUHash, 18 | MaxEntries: 1000000, 19 | EditorFlag: manager.EditMaxEntries | manager.EditType, 20 | }, 21 | }, 22 | RLimit: &unix.Rlimit{ 23 | Cur: math.MaxUint64, 24 | Max: math.MaxUint64, 25 | }, 26 | } 27 | 28 | // Initialize the manager 29 | if err := m.InitWithOptions(recoverAssets(), options); err != nil { 30 | logrus.Fatal(err) 31 | } 32 | 33 | logrus.Println("successfully loaded, checkout the parameters of the map \"cache\" using bpftool") 34 | 35 | wait() 36 | 37 | // Close the manager 38 | if err := m.Stop(manager.CleanAll); err != nil { 39 | logrus.Fatal(err) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /examples/mapspec_editor/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "os" 8 | "os/signal" 9 | "time" 10 | 11 | "github.com/sirupsen/logrus" 12 | ) 13 | 14 | // recoverAssets - Recover ebpf asset 15 | func recoverAssets() io.ReaderAt { 16 | buf, err := Asset("/probe.o") 17 | if err != nil { 18 | logrus.Fatal(fmt.Errorf("error:%v, %s", err, "couldn't find asset")) 19 | } 20 | return bytes.NewReader(buf) 21 | } 22 | 23 | // wait - Waits until an interrupt or kill signal is sent 24 | func wait() { 25 | logrus.Println("run next testcase after 3 second") 26 | time.Sleep(time.Second * 3) 27 | return 28 | sig := make(chan os.Signal, 1) 29 | signal.Notify(sig, os.Interrupt, os.Kill) 30 | <-sig 31 | fmt.Println() 32 | } 33 | -------------------------------------------------------------------------------- /examples/object_pinning/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | ebpf/bin/ 3 | -------------------------------------------------------------------------------- /examples/object_pinning/Makefile: -------------------------------------------------------------------------------- 1 | all: build-ebpf build run 2 | 3 | build-ebpf: 4 | mkdir -p ebpf/bin 5 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 6 | -Wno-unused-value \ 7 | -Wno-pointer-sign \ 8 | -Wno-compare-distinct-pointer-types \ 9 | -Wunused \ 10 | -Wall \ 11 | -Werror \ 12 | -I/lib/modules/$$(uname -r)/build/include \ 13 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 14 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 15 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 16 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 17 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 18 | -O2 -emit-llvm \ 19 | ebpf/main.c \ 20 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe.o 21 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg main -prefix "ebpf/bin" -o "probe.go" "ebpf/bin/probe.o" 22 | 23 | build: 24 | go build -o bin/main . 25 | 26 | run: 27 | sudo bin/main --kill 28 | -------------------------------------------------------------------------------- /examples/object_pinning/ebpf/include/bpf_map.h: -------------------------------------------------------------------------------- 1 | #define BUF_SIZE_MAP_NS 256 2 | 3 | typedef struct bpf_map_def { 4 | unsigned int type; 5 | unsigned int key_size; 6 | unsigned int value_size; 7 | unsigned int max_entries; 8 | unsigned int map_flags; 9 | unsigned int inner_map_idx; 10 | unsigned int pinning; 11 | char namespace[BUF_SIZE_MAP_NS]; 12 | } bpf_map_def; 13 | 14 | enum bpf_pin_type { 15 | PIN_NONE = 0, 16 | PIN_OBJECT_NS, 17 | PIN_GLOBAL_NS, 18 | PIN_CUSTOM_NS, 19 | }; 20 | -------------------------------------------------------------------------------- /examples/object_pinning/ebpf/main.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_map.h" 3 | #include "include/bpf_helpers.h" 4 | 5 | struct bpf_map_def SEC("maps/map1") map1 = { 6 | .type = BPF_MAP_TYPE_HASH, 7 | .key_size = sizeof(u32), 8 | .value_size = sizeof(u32), 9 | .max_entries = 10, 10 | }; 11 | 12 | struct bpf_map_def SEC("maps/map2") map2 = { 13 | .type = BPF_MAP_TYPE_HASH, 14 | .key_size = sizeof(u32), 15 | .value_size = sizeof(u32), 16 | .max_entries = 10, 17 | }; 18 | 19 | __attribute__((always_inline)) static int mkdir(int t) { 20 | // Check if map has some data 21 | u32 key = 1; 22 | u32 *data = bpf_map_lookup_elem(&map1, &key); 23 | if (data == NULL) { 24 | bpf_printk("(mkdir %d) map1 is empty\n", t); 25 | } else { 26 | bpf_printk("(mkdir %d) map1 contains %d at %d\n", t, *data, key); 27 | } 28 | return 0; 29 | }; 30 | 31 | __attribute__((always_inline)) static int mkdir_ret(int t) { 32 | u32 key = 1; 33 | u32 value = 42; 34 | u32 *data = bpf_map_lookup_elem(&map1, &key); 35 | if (data == NULL) { 36 | bpf_printk("(mkdirat ret %d) inserting %d at %d in map1\n", t, value, key); 37 | bpf_map_update_elem(&map1, &key, &value, BPF_ANY); 38 | } else { 39 | bpf_printk("(mkdirat ret %d) data already there, nothing to do\n", t); 40 | } 41 | return 0; 42 | }; 43 | 44 | SEC("kprobe/mkdir") 45 | int kprobe_mkdir(void *ctx) { 46 | return mkdir(1); 47 | } 48 | 49 | SEC("kprobe/mkdirat") 50 | int kprobe_mkdirat(void *ctx) 51 | { 52 | return mkdir(2); 53 | } 54 | 55 | SEC("kretprobe/mkdir") 56 | int kretprobe_mkdir(void *ctx) 57 | { 58 | return mkdir_ret(1); 59 | } 60 | 61 | SEC("kretprobe/mkdirat") 62 | int kretprobe_mkdirat(void *ctx) 63 | { 64 | return mkdir_ret(2); 65 | } 66 | 67 | char _license[] SEC("license") = "GPL"; 68 | __u32 _version SEC("version") = 0xFFFFFFFE; 69 | -------------------------------------------------------------------------------- /examples/object_pinning/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "github.com/gojue/ebpfmanager" 6 | "github.com/sirupsen/logrus" 7 | ) 8 | 9 | var m = &manager.Manager{ 10 | Probes: []*manager.Probe{ 11 | { 12 | Section: "kprobe/mkdirat", 13 | PinPath: "/sys/fs/bpf/mkdirat", 14 | AttachToFuncName: "mkdirat", 15 | EbpfFuncName: "kprobe_mkdirat", 16 | }, 17 | { 18 | Section: "kretprobe/mkdirat", 19 | AttachToFuncName: "mkdirat", 20 | EbpfFuncName: "kretprobe_mkdirat", 21 | }, 22 | { 23 | Section: "kprobe/mkdir", 24 | PinPath: "/sys/fs/bpf/mkdir", 25 | AttachToFuncName: "mkdir", 26 | EbpfFuncName: "kprobe_mkdir", 27 | }, 28 | { 29 | Section: "kretprobe/mkdir", 30 | AttachToFuncName: "mkdir", 31 | EbpfFuncName: "kretprobe_mkdir", 32 | }, 33 | }, 34 | Maps: []*manager.Map{ 35 | { 36 | Name: "map1", 37 | MapOptions: manager.MapOptions{ 38 | PinPath: "/sys/fs/bpf/map1", 39 | }, 40 | }, 41 | }, 42 | } 43 | 44 | func main() { 45 | // Parse CLI arguments 46 | var kill bool 47 | flag.BoolVar(&kill, "kill", false, "kills the programs suddenly before doing any cleanup") 48 | flag.Parse() 49 | 50 | logrus.Println("if they exist, pinned object will be automatically loaded") 51 | 52 | // Initialize the manager 53 | if err := m.Init(recoverAssets()); err != nil { 54 | logrus.Fatal(err) 55 | } 56 | 57 | // Start the manager 58 | if err := m.Start(); err != nil { 59 | logrus.Fatal(err) 60 | } 61 | 62 | logrus.Println("successfully started, head over to /sys/kernel/debug/tracing/trace_pipe") 63 | 64 | // Create a folder to trigger the probes 65 | if err := trigger(); err != nil { 66 | logrus.Error(err) 67 | } 68 | 69 | if kill { 70 | logrus.Println("=> Stopping the program without cleanup, the pinned map and programs should show up in /sys/fs/bpf/") 71 | logrus.Println("=> Restart without --kill to load the pinned object from the bpf file system and properly remove them") 72 | return 73 | } 74 | 75 | // Close the manager 76 | if err := m.Stop(manager.CleanAll); err != nil { 77 | logrus.Fatal(err) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /examples/object_pinning/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "os" 8 | 9 | "errors" 10 | "github.com/sirupsen/logrus" 11 | ) 12 | 13 | // recoverAssets - Recover ebpf asset 14 | func recoverAssets() io.ReaderAt { 15 | buf, err := Asset("/probe.o") 16 | if err != nil { 17 | logrus.Fatal(errors.New(fmt.Sprintf("error:%v , couldn't find asset", err))) 18 | } 19 | return bytes.NewReader(buf) 20 | } 21 | 22 | // trigger - Creates and then removes a tmp folder to trigger the probes 23 | func trigger() error { 24 | logrus.Println("Generating events to trigger the probes ...") 25 | // Creating a tmp directory to trigger the probes 26 | tmpDir := "/tmp/test_folder" 27 | logrus.Printf("creating %v", tmpDir) 28 | err := os.MkdirAll(tmpDir, 0666) 29 | if err != nil { 30 | return err 31 | } 32 | 33 | // Removing a tmp directory to trigger the probes 34 | logrus.Printf("removing %v", tmpDir) 35 | return os.RemoveAll(tmpDir) 36 | } 37 | -------------------------------------------------------------------------------- /examples/program_router/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | ebpf/bin/ 3 | -------------------------------------------------------------------------------- /examples/program_router/Makefile: -------------------------------------------------------------------------------- 1 | all: build-prog1 build-prog2 build run 2 | 3 | build-prog1: 4 | mkdir -p ebpf/bin 5 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 6 | -Wno-unused-value \ 7 | -Wno-pointer-sign \ 8 | -Wno-compare-distinct-pointer-types \ 9 | -Wunused \ 10 | -Wall \ 11 | -Werror \ 12 | -I/lib/modules/$$(uname -r)/build/include \ 13 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 14 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 15 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 16 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 17 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 18 | -O2 -emit-llvm \ 19 | ebpf/prog1.c \ 20 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe1.o 21 | 22 | build-prog2: 23 | mkdir -p ebpf/bin 24 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 25 | -Wno-unused-value \ 26 | -Wno-pointer-sign \ 27 | -Wno-compare-distinct-pointer-types \ 28 | -Wunused \ 29 | -Wall \ 30 | -Werror \ 31 | -I/lib/modules/$$(uname -r)/build/include \ 32 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 33 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 34 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 35 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 36 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 37 | -O2 -emit-llvm \ 38 | ebpf/prog2.c \ 39 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe2.o 40 | 41 | build: 42 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg main -prefix "ebpf/bin" -o "probe.go" "ebpf/bin/probe1.o" "ebpf/bin/probe2.o" 43 | go build -o bin/main . 44 | 45 | run: 46 | sudo bin/main 47 | -------------------------------------------------------------------------------- /examples/program_router/demo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/sirupsen/logrus" 7 | 8 | "github.com/gojue/ebpfmanager" 9 | ) 10 | 11 | func demoTailCall() error { 12 | logrus.Println("generating some traffic to show what happens when the tail call is not set up ...") 13 | trigger() 14 | time.Sleep(1 * time.Second) 15 | 16 | prog, _, err := m2.GetProgram(manager.ProbeIdentificationPair{EbpfFuncName: "classifier_three"}) 17 | if err != nil { 18 | logrus.Fatal(err) 19 | } 20 | 21 | // prepare tail call 22 | routes := []manager.TailCallRoute{ 23 | { 24 | ProgArrayName: "tc_prog_array", 25 | Key: uint32(1), 26 | ProbeIdentificationPair: manager.ProbeIdentificationPair{ 27 | EbpfFuncName: "classifier_two", 28 | }, 29 | }, 30 | { 31 | ProgArrayName: "tc_prog_array", 32 | Key: uint32(2), 33 | Program: prog[0], 34 | }, 35 | } 36 | 37 | // Map programs 38 | if err := m.UpdateTailCallRoutes(routes...); err != nil { 39 | return err 40 | } 41 | logrus.Println("generating some traffic to show what happens when the tail call is set up ...") 42 | trigger() 43 | return nil 44 | } 45 | -------------------------------------------------------------------------------- /examples/program_router/ebpf/include/bpf_map.h: -------------------------------------------------------------------------------- 1 | #define BUF_SIZE_MAP_NS 256 2 | 3 | typedef struct bpf_map_def { 4 | unsigned int type; 5 | unsigned int key_size; 6 | unsigned int value_size; 7 | unsigned int max_entries; 8 | unsigned int map_flags; 9 | unsigned int inner_map_idx; 10 | unsigned int pinning; 11 | char namespace[BUF_SIZE_MAP_NS]; 12 | } bpf_map_def; 13 | 14 | enum bpf_pin_type { 15 | PIN_NONE = 0, 16 | PIN_OBJECT_NS, 17 | PIN_GLOBAL_NS, 18 | PIN_CUSTOM_NS, 19 | }; 20 | -------------------------------------------------------------------------------- /examples/program_router/ebpf/prog1.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_map.h" 3 | #include "include/bpf_helpers.h" 4 | 5 | #include 6 | 7 | #define TAIL_CALL_KEY 1 8 | #define EXTERNAL_TAIL_CALL_KEY 2 9 | 10 | struct bpf_map_def SEC("maps/tc_prog_array") tc_prog_array = { 11 | .type = BPF_MAP_TYPE_PROG_ARRAY, 12 | .key_size = 4, 13 | .value_size = 4, 14 | .max_entries = 3, 15 | }; 16 | 17 | SEC("classifier/one") 18 | int classifier_one(struct __sk_buff *skb) 19 | { 20 | bpf_printk("(classifier/one) new packet captured (TC)\n"); 21 | 22 | // Tail call 23 | int key = TAIL_CALL_KEY; 24 | bpf_tail_call(skb, &tc_prog_array, key); 25 | 26 | // Tail call failed 27 | bpf_printk("(classifier/one) couldn't tail call (TC)\n"); 28 | return TC_ACT_OK; 29 | }; 30 | 31 | SEC("classifier/two") 32 | int classifier_two(struct __sk_buff *skb) 33 | { 34 | bpf_printk("(classifier/two) tail call triggered (TC)\n"); 35 | 36 | // Tail call 37 | int key = EXTERNAL_TAIL_CALL_KEY; 38 | bpf_tail_call(skb, &tc_prog_array, key); 39 | 40 | // Tail call failed 41 | bpf_printk("(classifier/two) external tail call failed (TC)\n"); 42 | return TC_ACT_OK; 43 | }; 44 | 45 | char _license[] SEC("license") = "GPL"; 46 | __u32 _version SEC("version") = 0xFFFFFFFE; 47 | -------------------------------------------------------------------------------- /examples/program_router/ebpf/prog2.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_map.h" 3 | #include "include/bpf_helpers.h" 4 | 5 | #include 6 | 7 | SEC("classifier/three") 8 | int classifier_three(struct __sk_buff *skb) 9 | { 10 | bpf_printk("(classifier/three) tail call triggered (TC)\n"); 11 | return TC_ACT_OK; 12 | }; 13 | 14 | char _license[] SEC("license") = "GPL"; 15 | __u32 _version SEC("version") = 0xFFFFFFFE; 16 | -------------------------------------------------------------------------------- /examples/program_router/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/sirupsen/logrus" 5 | 6 | "github.com/gojue/ebpfmanager" 7 | _ "github.com/shuLhan/go-bindata" 8 | ) 9 | 10 | var m = &manager.Manager{ 11 | Probes: []*manager.Probe{ 12 | { 13 | Section: "classifier/one", 14 | Ifname: "eth0", // change this to the interface index connected to the internet 15 | NetworkDirection: manager.Egress, 16 | EbpfFuncName: "classifier_one", 17 | }, 18 | }, 19 | } 20 | 21 | var m2 = &manager.Manager{ 22 | Probes: []*manager.Probe{}, 23 | } 24 | 25 | func main() { 26 | // Initialize the manager 27 | logrus.Println("ready to init probe1.o") 28 | if err := m.Init(recoverAssets("/probe1.o")); err != nil { 29 | logrus.Fatal(err) 30 | } 31 | 32 | logrus.Println("ready to init probe2.o") 33 | if err := m2.Init(recoverAssets("/probe2.o")); err != nil { 34 | logrus.Fatal(err) 35 | } 36 | 37 | // Start the manager 38 | if err := m.Start(); err != nil { 39 | logrus.Fatal(err) 40 | } 41 | if err := m2.Start(); err != nil { 42 | logrus.Fatal(err) 43 | } 44 | 45 | logrus.Println("successfully started, head over to /sys/kernel/debug/tracing/trace_pipe") 46 | 47 | if err := demoTailCall(); err != nil { 48 | logrus.Error(err) 49 | } 50 | 51 | // Close the manager 52 | if err := m.Stop(manager.CleanAll); err != nil { 53 | logrus.Fatal(err) 54 | } 55 | if err := m2.Stop(manager.CleanAll); err != nil { 56 | logrus.Fatal(err) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /examples/program_router/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "net/http" 8 | 9 | "errors" 10 | "github.com/sirupsen/logrus" 11 | ) 12 | 13 | // recoverAssets - Recover ebpf asset 14 | func recoverAssets(probe string) io.ReaderAt { 15 | buf, err := Asset(probe) 16 | if err != nil { 17 | logrus.Fatal(errors.New(fmt.Sprintf("error:%v , couldn't find asset", err))) 18 | } 19 | return bytes.NewReader(buf) 20 | } 21 | 22 | // trigger - Generate some network traffic to trigger the probe 23 | func trigger() { 24 | _, _ = http.Get("https://www.google.com/") 25 | } 26 | -------------------------------------------------------------------------------- /examples/programs/cgroup/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | ebpf/bin/ 3 | -------------------------------------------------------------------------------- /examples/programs/cgroup/Makefile: -------------------------------------------------------------------------------- 1 | all: build-ebpf build run 2 | 3 | build-ebpf: 4 | mkdir -p ebpf/bin 5 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 6 | -Wno-unused-value \ 7 | -Wno-pointer-sign \ 8 | -Wno-compare-distinct-pointer-types \ 9 | -Wunused \ 10 | -Wall \ 11 | -Werror \ 12 | -I/lib/modules/$$(uname -r)/build/include \ 13 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 14 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 15 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 16 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 17 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 18 | -O2 -emit-llvm \ 19 | ebpf/main.c \ 20 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe.o 21 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg main -prefix "ebpf/bin" -o "probe.go" "ebpf/bin/probe.o" 22 | 23 | build: 24 | go build -o bin/main . 25 | 26 | run: 27 | sudo bin/main 28 | -------------------------------------------------------------------------------- /examples/programs/cgroup/ebpf/include/bpf_helpers.h: -------------------------------------------------------------------------------- 1 | #ifndef __BPF_HELPERS_H 2 | #define __BPF_HELPERS_H 3 | 4 | #define bpf_printk(fmt, ...) \ 5 | ({ \ 6 | char ____fmt[] = fmt; \ 7 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 8 | ##__VA_ARGS__); \ 9 | }) 10 | 11 | /* helper macro to place programs, maps, license in 12 | * different sections in elf_bpf file. Section names 13 | * are interpreted by elf_bpf loader 14 | */ 15 | #define SEC(NAME) __attribute__((section(NAME), used)) 16 | 17 | /* helper functions called from eBPF programs written in C */ 18 | static void *(*bpf_map_lookup_elem)(void *map, void *key) = 19 | (void *)BPF_FUNC_map_lookup_elem; 20 | static int (*bpf_map_update_elem)(void *map, void *key, void *value, 21 | unsigned long long flags) = 22 | (void *)BPF_FUNC_map_update_elem; 23 | static int (*bpf_map_delete_elem)(void *map, void *key) = 24 | (void *)BPF_FUNC_map_delete_elem; 25 | static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) = 26 | (void *)BPF_FUNC_probe_read; 27 | static unsigned long long (*bpf_ktime_get_ns)(void) = 28 | (void *)BPF_FUNC_ktime_get_ns; 29 | static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = 30 | (void *)BPF_FUNC_trace_printk; 31 | static unsigned long long (*bpf_get_smp_processor_id)(void) = 32 | (void *)BPF_FUNC_get_smp_processor_id; 33 | static unsigned long long (*bpf_get_current_pid_tgid)(void) = 34 | (void *)BPF_FUNC_get_current_pid_tgid; 35 | static unsigned long long (*bpf_get_current_uid_gid)(void) = 36 | (void *)BPF_FUNC_get_current_uid_gid; 37 | static int (*bpf_get_current_comm)(void *buf, int buf_size) = 38 | (void *)BPF_FUNC_get_current_comm; 39 | static int (*bpf_perf_event_read)(void *map, int index) = 40 | (void *)BPF_FUNC_perf_event_read; 41 | static int (*bpf_clone_redirect)(void *ctx, int ifindex, int flags) = 42 | (void *)BPF_FUNC_clone_redirect; 43 | static int (*bpf_redirect)(int ifindex, int flags) = 44 | (void *)BPF_FUNC_redirect; 45 | static int (*bpf_perf_event_output)(void *ctx, void *map, 46 | unsigned long long flags, void *data, 47 | int size) = 48 | (void *)BPF_FUNC_perf_event_output; 49 | static int (*bpf_skb_get_tunnel_key)(void *ctx, void *key, int size, int flags) = 50 | (void *)BPF_FUNC_skb_get_tunnel_key; 51 | static int (*bpf_skb_set_tunnel_key)(void *ctx, void *key, int size, int flags) = 52 | (void *)BPF_FUNC_skb_set_tunnel_key; 53 | static unsigned long long (*bpf_get_prandom_u32)(void) = 54 | (void *)BPF_FUNC_get_prandom_u32; 55 | 56 | /* llvm builtin functions that eBPF C program may use to 57 | * emit BPF_LD_ABS and BPF_LD_IND instructions 58 | */ 59 | struct sk_buff; 60 | unsigned long long load_byte(void *skb, 61 | unsigned long long off) asm("llvm.bpf.load.byte"); 62 | unsigned long long load_half(void *skb, 63 | unsigned long long off) asm("llvm.bpf.load.half"); 64 | unsigned long long load_word(void *skb, 65 | unsigned long long off) asm("llvm.bpf.load.word"); 66 | 67 | /* a helper structure used by eBPF C program 68 | * to describe map attributes to elf_bpf loader 69 | */ 70 | #define BUF_SIZE_MAP_NS 256 71 | 72 | // struct bpf_map_def 73 | // { 74 | // unsigned int type; 75 | // unsigned int key_size; 76 | // unsigned int value_size; 77 | // unsigned int max_entries; 78 | // unsigned int map_flags; 79 | // unsigned int pinning; 80 | // char namespace[BUF_SIZE_MAP_NS]; 81 | // }; 82 | 83 | static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = 84 | (void *)BPF_FUNC_skb_store_bytes; 85 | static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) = 86 | (void *)BPF_FUNC_l3_csum_replace; 87 | static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) = 88 | (void *)BPF_FUNC_l4_csum_replace; 89 | 90 | #if defined(__x86_64__) 91 | 92 | #define PT_REGS_PARM1(x) ((x)->di) 93 | #define PT_REGS_PARM2(x) ((x)->si) 94 | #define PT_REGS_PARM3(x) ((x)->dx) 95 | #define PT_REGS_PARM4(x) ((x)->cx) 96 | #define PT_REGS_PARM5(x) ((x)->r8) 97 | #define PT_REGS_RET(x) ((x)->sp) 98 | #define PT_REGS_FP(x) ((x)->bp) 99 | #define PT_REGS_RC(x) ((x)->ax) 100 | #define PT_REGS_SP(x) ((x)->sp) 101 | #define PT_REGS_IP(x) ((x)->ip) 102 | 103 | #elif defined(__s390x__) 104 | 105 | #define PT_REGS_PARM1(x) ((x)->gprs[2]) 106 | #define PT_REGS_PARM2(x) ((x)->gprs[3]) 107 | #define PT_REGS_PARM3(x) ((x)->gprs[4]) 108 | #define PT_REGS_PARM4(x) ((x)->gprs[5]) 109 | #define PT_REGS_PARM5(x) ((x)->gprs[6]) 110 | #define PT_REGS_RET(x) ((x)->gprs[14]) 111 | #define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */ 112 | #define PT_REGS_RC(x) ((x)->gprs[2]) 113 | #define PT_REGS_SP(x) ((x)->gprs[15]) 114 | #define PT_REGS_IP(x) ((x)->ip) 115 | 116 | #elif defined(__aarch64__) 117 | 118 | #define PT_REGS_PARM1(x) ((x)->regs[0]) 119 | #define PT_REGS_PARM2(x) ((x)->regs[1]) 120 | #define PT_REGS_PARM3(x) ((x)->regs[2]) 121 | #define PT_REGS_PARM4(x) ((x)->regs[3]) 122 | #define PT_REGS_PARM5(x) ((x)->regs[4]) 123 | #define PT_REGS_RET(x) ((x)->regs[30]) 124 | #define PT_REGS_FP(x) ((x)->regs[29]) /* Works only with CONFIG_FRAME_POINTER */ 125 | #define PT_REGS_RC(x) ((x)->regs[0]) 126 | #define PT_REGS_SP(x) ((x)->sp) 127 | #define PT_REGS_IP(x) ((x)->pc) 128 | 129 | #elif defined(__powerpc__) 130 | 131 | #define PT_REGS_PARM1(x) ((x)->gpr[3]) 132 | #define PT_REGS_PARM2(x) ((x)->gpr[4]) 133 | #define PT_REGS_PARM3(x) ((x)->gpr[5]) 134 | #define PT_REGS_PARM4(x) ((x)->gpr[6]) 135 | #define PT_REGS_PARM5(x) ((x)->gpr[7]) 136 | #define PT_REGS_RC(x) ((x)->gpr[3]) 137 | #define PT_REGS_SP(x) ((x)->sp) 138 | #define PT_REGS_IP(x) ((x)->nip) 139 | 140 | #endif 141 | 142 | #ifdef __powerpc__ 143 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) 144 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP 145 | #else 146 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) 147 | #define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), \ 148 | (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) 149 | #endif 150 | 151 | #endif 152 | -------------------------------------------------------------------------------- /examples/programs/cgroup/ebpf/main.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_helpers.h" 3 | 4 | SEC("cgroup_skb/egress") 5 | int cgroup_egress_func(struct __sk_buff *skb) 6 | { 7 | bpf_printk("new packet captured on cgroup egress\n"); 8 | return 1; 9 | }; 10 | 11 | char _license[] SEC("license") = "GPL"; 12 | __u32 _version SEC("version") = 0xFFFFFFFE; 13 | -------------------------------------------------------------------------------- /examples/programs/cgroup/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "github.com/gojue/ebpfmanager" 7 | "github.com/sirupsen/logrus" 8 | "os" 9 | "strings" 10 | ) 11 | 12 | var m = &manager.Manager{ 13 | Probes: []*manager.Probe{ 14 | { 15 | //Section: "cgroup_skb/egress", 16 | //CGroupPath: "/sys/fs/cgroup/unified", 17 | EbpfFuncName: "cgroup_egress_func", 18 | Section: "cgroup_skb/egress", 19 | }, 20 | }, 21 | } 22 | 23 | func main() { 24 | cp, err := detectCgroupPath() 25 | if err != nil { 26 | logrus.Fatal(err) 27 | } 28 | m.Probes[0].CGroupPath = cp 29 | 30 | // Initialize the manager 31 | if err := m.Init(recoverAssets()); err != nil { 32 | logrus.Fatal(err) 33 | } 34 | 35 | // Start the manager 36 | if err := m.Start(); err != nil { 37 | logrus.Fatal(err) 38 | } 39 | 40 | logrus.Println("successfully started, head over to /sys/kernel/debug/tracing/trace_pipe") 41 | 42 | // Generate some network traffic to trigger the probe 43 | trigger() 44 | 45 | // Close the manager 46 | if err := m.Stop(manager.CleanAll); err != nil { 47 | logrus.Fatal(err) 48 | } 49 | } 50 | 51 | func detectCgroupPath() (string, error) { 52 | f, err := os.Open("/proc/mounts") 53 | if err != nil { 54 | return "", err 55 | } 56 | defer f.Close() 57 | 58 | scanner := bufio.NewScanner(f) 59 | for scanner.Scan() { 60 | fields := strings.Split(scanner.Text(), " ") 61 | if len(fields) >= 3 && fields[2] == "cgroup2" { 62 | return fields[1], nil 63 | } 64 | } 65 | 66 | return "", errors.New("cgroup2 is not mounted") 67 | } 68 | -------------------------------------------------------------------------------- /examples/programs/cgroup/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "github.com/sirupsen/logrus" 8 | "io" 9 | "net/http" 10 | ) 11 | 12 | // recoverAssets - Recover ebpf asset 13 | func recoverAssets() io.ReaderAt { 14 | buf, err := Asset("/probe.o") 15 | if err != nil { 16 | logrus.Fatal(errors.New(fmt.Sprintf("error:%v , couldn't find asset", err))) 17 | } 18 | return bytes.NewReader(buf) 19 | } 20 | 21 | // trigger - Generate some network traffic to trigger the probe 22 | func trigger() { 23 | logrus.Println("Generating some network traffic to trigger the probes ...") 24 | _, _ = http.Get("https://www.google.com/") 25 | } 26 | -------------------------------------------------------------------------------- /examples/programs/kprobe/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | ebpf/bin/ 3 | -------------------------------------------------------------------------------- /examples/programs/kprobe/Makefile: -------------------------------------------------------------------------------- 1 | all: build-ebpf build run 2 | 3 | build-ebpf: 4 | mkdir -p ebpf/bin 5 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 6 | -Wno-unused-value \ 7 | -Wno-pointer-sign \ 8 | -Wno-compare-distinct-pointer-types \ 9 | -Wunused \ 10 | -Wall \ 11 | -Werror \ 12 | -I/lib/modules/$$(uname -r)/build/include \ 13 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 14 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 15 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 16 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 17 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 18 | -O2 -emit-llvm \ 19 | ebpf/main.c \ 20 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe.o 21 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg main -prefix "ebpf/bin" -o "probe.go" "ebpf/bin/probe.o" 22 | 23 | build: 24 | go build -o bin/main . 25 | 26 | run: 27 | sudo bin/main 28 | -------------------------------------------------------------------------------- /examples/programs/kprobe/ebpf/include/bpf_helpers.h: -------------------------------------------------------------------------------- 1 | #ifndef __BPF_HELPERS_H 2 | #define __BPF_HELPERS_H 3 | 4 | #define bpf_printk(fmt, ...) \ 5 | ({ \ 6 | char ____fmt[] = fmt; \ 7 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 8 | ##__VA_ARGS__); \ 9 | }) 10 | 11 | /* helper macro to place programs, maps, license in 12 | * different sections in elf_bpf file. Section names 13 | * are interpreted by elf_bpf loader 14 | */ 15 | #define SEC(NAME) __attribute__((section(NAME), used)) 16 | 17 | /* helper functions called from eBPF programs written in C */ 18 | static void *(*bpf_map_lookup_elem)(void *map, void *key) = 19 | (void *)BPF_FUNC_map_lookup_elem; 20 | static int (*bpf_map_update_elem)(void *map, void *key, void *value, 21 | unsigned long long flags) = 22 | (void *)BPF_FUNC_map_update_elem; 23 | static int (*bpf_map_delete_elem)(void *map, void *key) = 24 | (void *)BPF_FUNC_map_delete_elem; 25 | static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) = 26 | (void *)BPF_FUNC_probe_read; 27 | static unsigned long long (*bpf_ktime_get_ns)(void) = 28 | (void *)BPF_FUNC_ktime_get_ns; 29 | static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = 30 | (void *)BPF_FUNC_trace_printk; 31 | static unsigned long long (*bpf_get_smp_processor_id)(void) = 32 | (void *)BPF_FUNC_get_smp_processor_id; 33 | static unsigned long long (*bpf_get_current_pid_tgid)(void) = 34 | (void *)BPF_FUNC_get_current_pid_tgid; 35 | static unsigned long long (*bpf_get_current_uid_gid)(void) = 36 | (void *)BPF_FUNC_get_current_uid_gid; 37 | static int (*bpf_get_current_comm)(void *buf, int buf_size) = 38 | (void *)BPF_FUNC_get_current_comm; 39 | static int (*bpf_perf_event_read)(void *map, int index) = 40 | (void *)BPF_FUNC_perf_event_read; 41 | static int (*bpf_clone_redirect)(void *ctx, int ifindex, int flags) = 42 | (void *)BPF_FUNC_clone_redirect; 43 | static int (*bpf_redirect)(int ifindex, int flags) = 44 | (void *)BPF_FUNC_redirect; 45 | static int (*bpf_perf_event_output)(void *ctx, void *map, 46 | unsigned long long flags, void *data, 47 | int size) = 48 | (void *)BPF_FUNC_perf_event_output; 49 | static int (*bpf_skb_get_tunnel_key)(void *ctx, void *key, int size, int flags) = 50 | (void *)BPF_FUNC_skb_get_tunnel_key; 51 | static int (*bpf_skb_set_tunnel_key)(void *ctx, void *key, int size, int flags) = 52 | (void *)BPF_FUNC_skb_set_tunnel_key; 53 | static unsigned long long (*bpf_get_prandom_u32)(void) = 54 | (void *)BPF_FUNC_get_prandom_u32; 55 | 56 | /* llvm builtin functions that eBPF C program may use to 57 | * emit BPF_LD_ABS and BPF_LD_IND instructions 58 | */ 59 | struct sk_buff; 60 | unsigned long long load_byte(void *skb, 61 | unsigned long long off) asm("llvm.bpf.load.byte"); 62 | unsigned long long load_half(void *skb, 63 | unsigned long long off) asm("llvm.bpf.load.half"); 64 | unsigned long long load_word(void *skb, 65 | unsigned long long off) asm("llvm.bpf.load.word"); 66 | 67 | /* a helper structure used by eBPF C program 68 | * to describe map attributes to elf_bpf loader 69 | */ 70 | #define BUF_SIZE_MAP_NS 256 71 | 72 | // struct bpf_map_def 73 | // { 74 | // unsigned int type; 75 | // unsigned int key_size; 76 | // unsigned int value_size; 77 | // unsigned int max_entries; 78 | // unsigned int map_flags; 79 | // unsigned int pinning; 80 | // char namespace[BUF_SIZE_MAP_NS]; 81 | // }; 82 | 83 | static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = 84 | (void *)BPF_FUNC_skb_store_bytes; 85 | static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) = 86 | (void *)BPF_FUNC_l3_csum_replace; 87 | static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) = 88 | (void *)BPF_FUNC_l4_csum_replace; 89 | 90 | #if defined(__x86_64__) 91 | 92 | #define PT_REGS_PARM1(x) ((x)->di) 93 | #define PT_REGS_PARM2(x) ((x)->si) 94 | #define PT_REGS_PARM3(x) ((x)->dx) 95 | #define PT_REGS_PARM4(x) ((x)->cx) 96 | #define PT_REGS_PARM5(x) ((x)->r8) 97 | #define PT_REGS_RET(x) ((x)->sp) 98 | #define PT_REGS_FP(x) ((x)->bp) 99 | #define PT_REGS_RC(x) ((x)->ax) 100 | #define PT_REGS_SP(x) ((x)->sp) 101 | #define PT_REGS_IP(x) ((x)->ip) 102 | 103 | #elif defined(__s390x__) 104 | 105 | #define PT_REGS_PARM1(x) ((x)->gprs[2]) 106 | #define PT_REGS_PARM2(x) ((x)->gprs[3]) 107 | #define PT_REGS_PARM3(x) ((x)->gprs[4]) 108 | #define PT_REGS_PARM4(x) ((x)->gprs[5]) 109 | #define PT_REGS_PARM5(x) ((x)->gprs[6]) 110 | #define PT_REGS_RET(x) ((x)->gprs[14]) 111 | #define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */ 112 | #define PT_REGS_RC(x) ((x)->gprs[2]) 113 | #define PT_REGS_SP(x) ((x)->gprs[15]) 114 | #define PT_REGS_IP(x) ((x)->ip) 115 | 116 | #elif defined(__aarch64__) 117 | 118 | #define PT_REGS_PARM1(x) ((x)->regs[0]) 119 | #define PT_REGS_PARM2(x) ((x)->regs[1]) 120 | #define PT_REGS_PARM3(x) ((x)->regs[2]) 121 | #define PT_REGS_PARM4(x) ((x)->regs[3]) 122 | #define PT_REGS_PARM5(x) ((x)->regs[4]) 123 | #define PT_REGS_RET(x) ((x)->regs[30]) 124 | #define PT_REGS_FP(x) ((x)->regs[29]) /* Works only with CONFIG_FRAME_POINTER */ 125 | #define PT_REGS_RC(x) ((x)->regs[0]) 126 | #define PT_REGS_SP(x) ((x)->sp) 127 | #define PT_REGS_IP(x) ((x)->pc) 128 | 129 | #elif defined(__powerpc__) 130 | 131 | #define PT_REGS_PARM1(x) ((x)->gpr[3]) 132 | #define PT_REGS_PARM2(x) ((x)->gpr[4]) 133 | #define PT_REGS_PARM3(x) ((x)->gpr[5]) 134 | #define PT_REGS_PARM4(x) ((x)->gpr[6]) 135 | #define PT_REGS_PARM5(x) ((x)->gpr[7]) 136 | #define PT_REGS_RC(x) ((x)->gpr[3]) 137 | #define PT_REGS_SP(x) ((x)->sp) 138 | #define PT_REGS_IP(x) ((x)->nip) 139 | 140 | #endif 141 | 142 | #ifdef __powerpc__ 143 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) 144 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP 145 | #else 146 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) 147 | #define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), \ 148 | (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) 149 | #endif 150 | 151 | #endif 152 | -------------------------------------------------------------------------------- /examples/programs/kprobe/ebpf/main.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_helpers.h" 3 | 4 | SEC("kprobe/vfs_mkdir") 5 | int kprobe_vfs_mkdir(void *ctx) 6 | { 7 | bpf_printk("mkdir (vfs hook point)\n"); 8 | return 0; 9 | }; 10 | 11 | SEC("kprobe/utimes_common") 12 | int kprobe_utimes_common(void *ctx) 13 | { 14 | bpf_printk("utimes_common\n"); 15 | return 0; 16 | }; 17 | 18 | SEC("kretprobe/mkdirat") 19 | int kretpobe_unlinkat(void *ctx) 20 | { 21 | bpf_printk("mkdirat return (syscall hook point)\n"); 22 | return 0; 23 | } 24 | 25 | char _license[] SEC("license") = "GPL"; 26 | __u32 _version SEC("version") = 0xFFFFFFFE; 27 | -------------------------------------------------------------------------------- /examples/programs/kprobe/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gojue/ebpfmanager" 6 | "github.com/sirupsen/logrus" 7 | "os" 8 | "os/signal" 9 | "time" 10 | ) 11 | 12 | var m = &manager.Manager{ 13 | Probes: []*manager.Probe{ 14 | &manager.Probe{ 15 | UID: "MyVFSMkdir", 16 | Section: "kprobe/vfs_mkdir", 17 | EbpfFuncName: "kprobe_vfs_mkdir", 18 | AttachToFuncName: "vfs_mkdir", 19 | }, 20 | &manager.Probe{ 21 | UID: "", // UID is needed only if there are multiple instances of your program (after using 22 | // m.CloneProgram for example), or if multiple programs with the exact same section are attaching 23 | // at the exact same hook point (using m.AddHook for example, or simply because another manager 24 | // on the system is planning on hooking there). 25 | Section: "kretprobe/mkdirat", 26 | EbpfFuncName: "kretpobe_unlinkat", 27 | AttachToFuncName: "mkdirat", 28 | KProbeMaxActive: 100, 29 | }, 30 | }, 31 | } 32 | 33 | func main() { 34 | options := manager.Options{ 35 | DefaultProbeRetry: 2, 36 | DefaultProbeRetryDelay: time.Second, 37 | } 38 | 39 | // Initialize the manager 40 | if err := m.InitWithOptions(recoverAssets(), options); err != nil { 41 | logrus.Fatal(err) 42 | } 43 | 44 | // Start the manager 45 | if err := m.Start(); err != nil { 46 | logrus.Fatal(err) 47 | } 48 | 49 | logrus.Println("successfully started") 50 | logrus.Println("=> head over to /sys/kernel/debug/tracing/trace_pipe") 51 | logrus.Println("=> checkout /sys/kernel/debug/tracing/kprobe_events, utimes_common might have become utimes_common.isra.0") 52 | logrus.Println("=> Cmd+C to exit") 53 | 54 | // Create a folder to trigger the probes 55 | if err := trigger(); err != nil { 56 | logrus.Error(err) 57 | } 58 | 59 | wait() 60 | 61 | // Close the manager 62 | if err := m.Stop(manager.CleanAll); err != nil { 63 | logrus.Fatal(err) 64 | } 65 | } 66 | 67 | // wait - Waits until an interrupt or kill signal is sent 68 | func wait() { 69 | logrus.Println("run next testcase after 3 second") 70 | time.Sleep(time.Second * 3) 71 | return 72 | sig := make(chan os.Signal, 1) 73 | signal.Notify(sig, os.Interrupt, os.Kill) 74 | <-sig 75 | fmt.Println() 76 | } 77 | -------------------------------------------------------------------------------- /examples/programs/kprobe/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "os" 8 | 9 | "errors" 10 | "github.com/sirupsen/logrus" 11 | ) 12 | 13 | // recoverAssets - Recover ebpf asset 14 | func recoverAssets() io.ReaderAt { 15 | buf, err := Asset("/probe.o") 16 | if err != nil { 17 | logrus.Fatal(errors.New(fmt.Sprintf("error:%v , couldn't find asset", err))) 18 | } 19 | return bytes.NewReader(buf) 20 | } 21 | 22 | // trigger - Creates and then removes a tmp folder to trigger the probes 23 | func trigger() error { 24 | logrus.Println("Generating events to trigger the probes ...") 25 | // Creating a tmp directory to trigger the probes 26 | tmpDir := "/tmp/test_folder" 27 | logrus.Printf("creating %v", tmpDir) 28 | err := os.MkdirAll(tmpDir, 0666) 29 | if err != nil { 30 | return err 31 | } 32 | 33 | // Removing a tmp directory to trigger the probes 34 | logrus.Printf("removing %v", tmpDir) 35 | return os.RemoveAll(tmpDir) 36 | } 37 | 38 | -------------------------------------------------------------------------------- /examples/programs/lsm/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | ebpf/bin/ 3 | -------------------------------------------------------------------------------- /examples/programs/lsm/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Kernel Version detect 3 | # 4 | 5 | KERNEL_SUPPORT_LSM_FLAGS ?= 6 | # 获取内核版本 7 | 8 | KVER = $(shell uname -r) 9 | KMAJ = $(shell echo $(KVER) | \ 10 | sed -e 's/^\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*.*/\1/') 11 | KMIN = $(shell echo $(KVER) | \ 12 | sed -e 's/^[0-9][0-9]*\.\([0-9][0-9]*\)\.[0-9][0-9]*.*/\1/') 13 | KREV = $(shell echo $(KVER) | \ 14 | sed -e 's/^[0-9][0-9]*\.[0-9][0-9]*\.\([0-9][0-9]*\).*/\1/') 15 | 16 | kver_ge = $(shell \ 17 | echo test | awk '{if($(KMAJ) < $(1)) {print 0} else { \ 18 | if($(KMAJ) > $(1)) {print 1} else { \ 19 | if($(KMIN) < $(2)) {print 0} else { \ 20 | if($(KMIN) > $(2)) {print 1} else { \ 21 | if($(KREV) < $(3)) {print 0} else { print 1 } \ 22 | }}}}}' \ 23 | ) 24 | 25 | ARCH := $(shell uname -m) 26 | 27 | ifeq ($(ARCH),aarch64) 28 | # arch aarch64 29 | ARCH_TARGET := arm64 30 | else ifeq ($(ARCH),arm64) 31 | # arch arm64 32 | ARCH_TARGET := arm64 33 | else 34 | # other arch 35 | ARCH_TARGET := other 36 | endif 37 | 38 | ifeq ($(ARCH_TARGET),arm64) 39 | ifeq ($(call kver_ge,6,0,0),1) 40 | KERNEL_SUPPORT_LSM_FLAGS = -DKERNEL_SUPPORT_LSM 41 | else 42 | # The arch arm64 kernel version is less than 6.0 43 | endif 44 | else 45 | ifeq ($(call kver_ge,5,7,0),1) 46 | KERNEL_SUPPORT_LSM_FLAGS = -DKERNEL_SUPPORT_LSM 47 | else 48 | # The kernel version is less than 5.7 49 | endif 50 | endif 51 | 52 | all: build-ebpf build run 53 | 54 | build-ebpf: 55 | mkdir -p ebpf/bin 56 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 57 | $(KERNEL_SUPPORT_LSM_FLAGS) \ 58 | -Wno-unused-value \ 59 | -Wno-pointer-sign \ 60 | -Wno-compare-distinct-pointer-types \ 61 | -Wunused \ 62 | -Wall \ 63 | -Werror \ 64 | -I/lib/modules/$$(uname -r)/build/include \ 65 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 66 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 67 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 68 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 69 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 70 | -O2 -emit-llvm \ 71 | ebpf/main.c \ 72 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe.o 73 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg main -prefix "ebpf/bin" -o "probe.go" "ebpf/bin/probe.o" 74 | 75 | build: 76 | go build -o bin/main . 77 | 78 | run: 79 | sudo bin/main 80 | -------------------------------------------------------------------------------- /examples/programs/lsm/ebpf/include/bpf_helpers.h: -------------------------------------------------------------------------------- 1 | #ifndef __BPF_HELPERS_H 2 | #define __BPF_HELPERS_H 3 | 4 | #define bpf_printk(fmt, ...) \ 5 | ({ \ 6 | char ____fmt[] = fmt; \ 7 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 8 | ##__VA_ARGS__); \ 9 | }) 10 | 11 | /* helper macro to place programs, maps, license in 12 | * different sections in elf_bpf file. Section names 13 | * are interpreted by elf_bpf loader 14 | */ 15 | #define SEC(NAME) __attribute__((section(NAME), used)) 16 | 17 | /* helper functions called from eBPF programs written in C */ 18 | static void *(*bpf_map_lookup_elem)(void *map, void *key) = 19 | (void *)BPF_FUNC_map_lookup_elem; 20 | static int (*bpf_map_update_elem)(void *map, void *key, void *value, 21 | unsigned long long flags) = 22 | (void *)BPF_FUNC_map_update_elem; 23 | static int (*bpf_map_delete_elem)(void *map, void *key) = 24 | (void *)BPF_FUNC_map_delete_elem; 25 | static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) = 26 | (void *)BPF_FUNC_probe_read; 27 | static unsigned long long (*bpf_ktime_get_ns)(void) = 28 | (void *)BPF_FUNC_ktime_get_ns; 29 | static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = 30 | (void *)BPF_FUNC_trace_printk; 31 | static unsigned long long (*bpf_get_smp_processor_id)(void) = 32 | (void *)BPF_FUNC_get_smp_processor_id; 33 | static unsigned long long (*bpf_get_current_pid_tgid)(void) = 34 | (void *)BPF_FUNC_get_current_pid_tgid; 35 | static unsigned long long (*bpf_get_current_uid_gid)(void) = 36 | (void *)BPF_FUNC_get_current_uid_gid; 37 | static int (*bpf_get_current_comm)(void *buf, int buf_size) = 38 | (void *)BPF_FUNC_get_current_comm; 39 | static int (*bpf_perf_event_read)(void *map, int index) = 40 | (void *)BPF_FUNC_perf_event_read; 41 | static int (*bpf_clone_redirect)(void *ctx, int ifindex, int flags) = 42 | (void *)BPF_FUNC_clone_redirect; 43 | static int (*bpf_redirect)(int ifindex, int flags) = 44 | (void *)BPF_FUNC_redirect; 45 | static int (*bpf_perf_event_output)(void *ctx, void *map, 46 | unsigned long long flags, void *data, 47 | int size) = 48 | (void *)BPF_FUNC_perf_event_output; 49 | static int (*bpf_skb_get_tunnel_key)(void *ctx, void *key, int size, int flags) = 50 | (void *)BPF_FUNC_skb_get_tunnel_key; 51 | static int (*bpf_skb_set_tunnel_key)(void *ctx, void *key, int size, int flags) = 52 | (void *)BPF_FUNC_skb_set_tunnel_key; 53 | static unsigned long long (*bpf_get_prandom_u32)(void) = 54 | (void *)BPF_FUNC_get_prandom_u32; 55 | 56 | /* llvm builtin functions that eBPF C program may use to 57 | * emit BPF_LD_ABS and BPF_LD_IND instructions 58 | */ 59 | struct sk_buff; 60 | unsigned long long load_byte(void *skb, 61 | unsigned long long off) asm("llvm.bpf.load.byte"); 62 | unsigned long long load_half(void *skb, 63 | unsigned long long off) asm("llvm.bpf.load.half"); 64 | unsigned long long load_word(void *skb, 65 | unsigned long long off) asm("llvm.bpf.load.word"); 66 | 67 | /* a helper structure used by eBPF C program 68 | * to describe map attributes to elf_bpf loader 69 | */ 70 | #define BUF_SIZE_MAP_NS 256 71 | 72 | // struct bpf_map_def 73 | // { 74 | // unsigned int type; 75 | // unsigned int key_size; 76 | // unsigned int value_size; 77 | // unsigned int max_entries; 78 | // unsigned int map_flags; 79 | // unsigned int pinning; 80 | // char namespace[BUF_SIZE_MAP_NS]; 81 | // }; 82 | 83 | static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = 84 | (void *)BPF_FUNC_skb_store_bytes; 85 | static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) = 86 | (void *)BPF_FUNC_l3_csum_replace; 87 | static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) = 88 | (void *)BPF_FUNC_l4_csum_replace; 89 | 90 | #if defined(__x86_64__) 91 | 92 | #define PT_REGS_PARM1(x) ((x)->di) 93 | #define PT_REGS_PARM2(x) ((x)->si) 94 | #define PT_REGS_PARM3(x) ((x)->dx) 95 | #define PT_REGS_PARM4(x) ((x)->cx) 96 | #define PT_REGS_PARM5(x) ((x)->r8) 97 | #define PT_REGS_RET(x) ((x)->sp) 98 | #define PT_REGS_FP(x) ((x)->bp) 99 | #define PT_REGS_RC(x) ((x)->ax) 100 | #define PT_REGS_SP(x) ((x)->sp) 101 | #define PT_REGS_IP(x) ((x)->ip) 102 | 103 | #elif defined(__s390x__) 104 | 105 | #define PT_REGS_PARM1(x) ((x)->gprs[2]) 106 | #define PT_REGS_PARM2(x) ((x)->gprs[3]) 107 | #define PT_REGS_PARM3(x) ((x)->gprs[4]) 108 | #define PT_REGS_PARM4(x) ((x)->gprs[5]) 109 | #define PT_REGS_PARM5(x) ((x)->gprs[6]) 110 | #define PT_REGS_RET(x) ((x)->gprs[14]) 111 | #define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */ 112 | #define PT_REGS_RC(x) ((x)->gprs[2]) 113 | #define PT_REGS_SP(x) ((x)->gprs[15]) 114 | #define PT_REGS_IP(x) ((x)->ip) 115 | 116 | #elif defined(__aarch64__) 117 | 118 | #define PT_REGS_PARM1(x) ((x)->regs[0]) 119 | #define PT_REGS_PARM2(x) ((x)->regs[1]) 120 | #define PT_REGS_PARM3(x) ((x)->regs[2]) 121 | #define PT_REGS_PARM4(x) ((x)->regs[3]) 122 | #define PT_REGS_PARM5(x) ((x)->regs[4]) 123 | #define PT_REGS_RET(x) ((x)->regs[30]) 124 | #define PT_REGS_FP(x) ((x)->regs[29]) /* Works only with CONFIG_FRAME_POINTER */ 125 | #define PT_REGS_RC(x) ((x)->regs[0]) 126 | #define PT_REGS_SP(x) ((x)->sp) 127 | #define PT_REGS_IP(x) ((x)->pc) 128 | 129 | #elif defined(__powerpc__) 130 | 131 | #define PT_REGS_PARM1(x) ((x)->gpr[3]) 132 | #define PT_REGS_PARM2(x) ((x)->gpr[4]) 133 | #define PT_REGS_PARM3(x) ((x)->gpr[5]) 134 | #define PT_REGS_PARM4(x) ((x)->gpr[6]) 135 | #define PT_REGS_PARM5(x) ((x)->gpr[7]) 136 | #define PT_REGS_RC(x) ((x)->gpr[3]) 137 | #define PT_REGS_SP(x) ((x)->sp) 138 | #define PT_REGS_IP(x) ((x)->nip) 139 | 140 | #endif 141 | 142 | #ifdef __powerpc__ 143 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) 144 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP 145 | #else 146 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) 147 | #define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), \ 148 | (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) 149 | #endif 150 | 151 | #endif 152 | -------------------------------------------------------------------------------- /examples/programs/lsm/ebpf/main.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_helpers.h" 3 | 4 | #ifdef KERNEL_SUPPORT_LSM 5 | struct path; 6 | SEC("lsm/path_mkdir") 7 | int lsm_path_mkdir(const struct path *path) 8 | { 9 | bpf_printk("path_mkdir (LSM hook point)\n"); 10 | return 0; 11 | }; 12 | #endif 13 | 14 | char _license[] SEC("license") = "GPL"; 15 | __u32 _version SEC("version") = 0xFFFFFFFE; -------------------------------------------------------------------------------- /examples/programs/lsm/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/cilium/ebpf" 6 | "github.com/cilium/ebpf/features" 7 | "github.com/gojue/ebpfmanager/kernel" 8 | "os" 9 | "os/signal" 10 | "runtime" 11 | "time" 12 | 13 | manager "github.com/gojue/ebpfmanager" 14 | "github.com/sirupsen/logrus" 15 | ) 16 | 17 | var m = &manager.Manager{ 18 | Probes: []*manager.Probe{ 19 | &manager.Probe{ 20 | UID: "MyLSMPathMkdirHook", 21 | Section: "lsm/path_mkdir", 22 | EbpfFuncName: "lsm_path_mkdir", 23 | AttachToFuncName: "path_mkdir", 24 | }, 25 | }, 26 | } 27 | 28 | func main() { 29 | if features.HaveProgramType(ebpf.LSM) != nil { 30 | return 31 | } 32 | lvc, err := features.LinuxVersionCode() 33 | if err != nil { 34 | return 35 | } 36 | //Check whether the arch arm64/aarch64 environment kernel version >= 6 37 | if runtime.GOARCH == "arm64" && (lvc>>16) < 6 { 38 | // LSM unsupported 39 | return 40 | } 41 | 42 | // Linux kernel version >= 5.7 43 | logrus.Println("initializing manager") 44 | kv, err := kernel.HostVersion() 45 | if err != nil { 46 | // nothing to do. 47 | } 48 | if kv < kernel.VersionCode(5, 7, 0) { 49 | logrus.Println(manager.ErrLSMNotSupported, "current kernel version is:", kv.String()) 50 | return 51 | } 52 | 53 | // Run the cat /boot/config-$(uname -r) | grep BPF_LSM command to check whether the LSM is supported 54 | // check CONFIG_BPF_LSM=y 55 | logrus.Println("cat /boot/config-$(uname -r) | grep BPF_LSM") 56 | isSupportLSM := checkSupportLSM() 57 | if !isSupportLSM { 58 | logrus.Println(manager.ErrLSMNotSupported, "Linux kernel does not support CONFIG_BPF_LSM=y") 59 | return 60 | } else { 61 | logrus.Println("Linux kernel supports CONFIG_BPF_LSM=y") 62 | } 63 | 64 | options := manager.Options{ 65 | DefaultProbeRetry: 2, 66 | DefaultProbeRetryDelay: time.Second, 67 | } 68 | 69 | // Initialize the manager 70 | if err := m.InitWithOptions(recoverAssets(), options); err != nil { 71 | logrus.Fatal(err) 72 | } 73 | 74 | // Start the manager 75 | if err := m.Start(); err != nil { 76 | logrus.Fatal(err) 77 | } 78 | 79 | logrus.Println("successfully started") 80 | logrus.Println("=> head over to /sys/kernel/debug/tracing/trace_pipe") 81 | logrus.Println("=> checkout /sys/kernel/debug/tracing/kprobe_events, utimes_common might have become utimes_common.isra.0") 82 | logrus.Println("=> Cmd+C to exit") 83 | 84 | // Create a folder to trigger the probes 85 | if err := trigger(); err != nil { 86 | logrus.Error(err) 87 | } 88 | 89 | wait() 90 | 91 | // Close the manager 92 | if err := m.Stop(manager.CleanAll); err != nil { 93 | logrus.Fatal(err) 94 | } 95 | } 96 | 97 | // wait - Waits until an interrupt or kill signal is sent 98 | func wait() { 99 | logrus.Println("run next testcase after 3 second") 100 | time.Sleep(time.Second * 3) 101 | return 102 | sig := make(chan os.Signal, 1) 103 | signal.Notify(sig, os.Interrupt, os.Kill) 104 | <-sig 105 | fmt.Println() 106 | } 107 | -------------------------------------------------------------------------------- /examples/programs/lsm/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "fmt" 7 | "io" 8 | "os" 9 | "strings" 10 | "syscall" 11 | 12 | "errors" 13 | "github.com/sirupsen/logrus" 14 | ) 15 | 16 | // recoverAssets - Recover ebpf asset 17 | func recoverAssets() io.ReaderAt { 18 | buf, err := Asset("/probe.o") 19 | if err != nil { 20 | logrus.Fatal(errors.New(fmt.Sprintf("error:%v , couldn't find asset", err))) 21 | } 22 | return bytes.NewReader(buf) 23 | } 24 | 25 | // trigger - Creates and then removes a tmp folder to trigger the probes 26 | func trigger() error { 27 | logrus.Println("Generating events to trigger the probes ...") 28 | // Creating a tmp directory to trigger the probes 29 | tmpDir := "/tmp/test_folder" 30 | logrus.Printf("creating %v", tmpDir) 31 | err := os.MkdirAll(tmpDir, 0666) 32 | if err != nil { 33 | return err 34 | } 35 | 36 | // Removing a tmp directory to trigger the probes 37 | logrus.Printf("removing %v", tmpDir) 38 | return os.RemoveAll(tmpDir) 39 | } 40 | 41 | // Convert null-terminated int8 slice to byte slice 42 | func int8SliceToByte(s []int8) []byte { 43 | var b []byte 44 | for _, v := range s { 45 | if v == 0 { 46 | break 47 | } 48 | b = append(b, byte(v)) 49 | } 50 | return b 51 | } 52 | 53 | // Convert null-terminated byte slice to Go string 54 | func byteToString(b []byte) string { 55 | return string(b) 56 | } 57 | 58 | func checkSupportLSM() bool { 59 | var uname syscall.Utsname 60 | if err := syscall.Uname(&uname); err != nil { 61 | return false 62 | } 63 | 64 | release := byteToString(int8SliceToByte(uname.Release[:])) 65 | bootConfigPath := fmt.Sprintf("/boot/config-%s", release) 66 | file, err := os.Open(bootConfigPath) 67 | if err != nil { 68 | return false 69 | } 70 | defer file.Close() 71 | 72 | scanner := bufio.NewScanner(file) 73 | for scanner.Scan() { 74 | line := scanner.Text() 75 | // check CONFIG_BPF_LSM=y 76 | if strings.HasPrefix(line, "CONFIG_BPF_LSM=y") || strings.HasPrefix(line, "CONFIG_BPF_LSM=Y") { 77 | return true 78 | } 79 | } 80 | 81 | if err := scanner.Err(); err != nil { 82 | return false 83 | } 84 | 85 | return false 86 | } 87 | -------------------------------------------------------------------------------- /examples/programs/rawtracepoint/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | ebpf/bin/ 3 | -------------------------------------------------------------------------------- /examples/programs/rawtracepoint/Makefile: -------------------------------------------------------------------------------- 1 | all: build-ebpf build run 2 | 3 | build-ebpf: 4 | mkdir -p ebpf/bin 5 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 6 | -Wno-unused-value \ 7 | -Wno-pointer-sign \ 8 | -Wno-compare-distinct-pointer-types \ 9 | -Wunused \ 10 | -Wall \ 11 | -Werror \ 12 | -I/lib/modules/$$(uname -r)/build/include \ 13 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 14 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 15 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 16 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 17 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 18 | -O2 -emit-llvm \ 19 | ebpf/main.c \ 20 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe.o 21 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg main -prefix "ebpf/bin" -o "probe.go" "ebpf/bin/probe.o" 22 | 23 | build: 24 | go build -o bin/main . 25 | 26 | run: 27 | sudo bin/main 28 | -------------------------------------------------------------------------------- /examples/programs/rawtracepoint/ebpf/main.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_helpers.h" 3 | 4 | SEC("raw_tracepoint/sys_enter") 5 | int raw_tracepoint_sys_enter(void *ctx) 6 | { 7 | bpf_printk("sys_enter enter (tracepoint)\n"); 8 | return 0; 9 | }; 10 | 11 | char _license[] SEC("license") = "GPL"; 12 | __u32 _version SEC("version") = 0xFFFFFFFE; 13 | -------------------------------------------------------------------------------- /examples/programs/rawtracepoint/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/sirupsen/logrus" 5 | 6 | manager "github.com/gojue/ebpfmanager" 7 | ) 8 | 9 | var m = &manager.Manager{ 10 | Probes: []*manager.Probe{ 11 | { 12 | Section: "raw_tracepoint/sys_enter", 13 | EbpfFuncName: "raw_tracepoint_sys_enter", 14 | }, 15 | }, 16 | } 17 | 18 | func main() { 19 | // Initialize the manager 20 | if err := m.Init(recoverAssets()); err != nil { 21 | logrus.Fatal(err) 22 | } 23 | 24 | // Start the manager 25 | if err := m.Start(); err != nil { 26 | logrus.Fatal(err) 27 | } 28 | 29 | logrus.Println("successfully started, head over to /sys/kernel/debug/tracing/trace_pipe") 30 | 31 | // Create a folder to trigger the probes 32 | if err := trigger(); err != nil { 33 | logrus.Error(err) 34 | } 35 | 36 | // Close the manager 37 | if err := m.Stop(manager.CleanAll); err != nil { 38 | logrus.Fatal(err) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/programs/rawtracepoint/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "os/exec" 8 | 9 | "errors" 10 | 11 | "github.com/sirupsen/logrus" 12 | ) 13 | 14 | // recoverAssets - Recover ebpf asset 15 | func recoverAssets() io.ReaderAt { 16 | buf, err := Asset("/probe.o") 17 | if err != nil { 18 | logrus.Fatal(errors.New(fmt.Sprintf("error:%v , couldn't find asset", err))) 19 | } 20 | return bytes.NewReader(buf) 21 | } 22 | 23 | // trigger - execute whoami to trigger the probes 24 | func trigger() error { 25 | logrus.Println("Generating events to trigger the probes ...") 26 | // Run whoami to trigger the event 27 | cmd := exec.Command("/usr/bin/whoami") 28 | return cmd.Run() 29 | } 30 | -------------------------------------------------------------------------------- /examples/programs/socket/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | ebpf/bin/ 3 | -------------------------------------------------------------------------------- /examples/programs/socket/Makefile: -------------------------------------------------------------------------------- 1 | all: build-ebpf build run 2 | 3 | build-ebpf: 4 | mkdir -p ebpf/bin 5 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 6 | -Wno-unused-value \ 7 | -Wno-pointer-sign \ 8 | -Wno-compare-distinct-pointer-types \ 9 | -Wunused \ 10 | -Wall \ 11 | -Werror \ 12 | -I/lib/modules/$$(uname -r)/build/include \ 13 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 14 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 15 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 16 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 17 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 18 | -O2 -emit-llvm \ 19 | ebpf/main.c \ 20 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe.o 21 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg main -prefix "ebpf/bin" -o "probe.go" "ebpf/bin/probe.o" 22 | 23 | build: 24 | go build -o bin/main . 25 | 26 | run: 27 | sudo bin/main 28 | -------------------------------------------------------------------------------- /examples/programs/socket/ebpf/include/bpf_helpers.h: -------------------------------------------------------------------------------- 1 | #ifndef __BPF_HELPERS_H 2 | #define __BPF_HELPERS_H 3 | 4 | #define bpf_printk(fmt, ...) \ 5 | ({ \ 6 | char ____fmt[] = fmt; \ 7 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 8 | ##__VA_ARGS__); \ 9 | }) 10 | 11 | /* helper macro to place programs, maps, license in 12 | * different sections in elf_bpf file. Section names 13 | * are interpreted by elf_bpf loader 14 | */ 15 | #define SEC(NAME) __attribute__((section(NAME), used)) 16 | 17 | /* helper functions called from eBPF programs written in C */ 18 | static void *(*bpf_map_lookup_elem)(void *map, void *key) = 19 | (void *)BPF_FUNC_map_lookup_elem; 20 | static int (*bpf_map_update_elem)(void *map, void *key, void *value, 21 | unsigned long long flags) = 22 | (void *)BPF_FUNC_map_update_elem; 23 | static int (*bpf_map_delete_elem)(void *map, void *key) = 24 | (void *)BPF_FUNC_map_delete_elem; 25 | static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) = 26 | (void *)BPF_FUNC_probe_read; 27 | static unsigned long long (*bpf_ktime_get_ns)(void) = 28 | (void *)BPF_FUNC_ktime_get_ns; 29 | static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = 30 | (void *)BPF_FUNC_trace_printk; 31 | static unsigned long long (*bpf_get_smp_processor_id)(void) = 32 | (void *)BPF_FUNC_get_smp_processor_id; 33 | static unsigned long long (*bpf_get_current_pid_tgid)(void) = 34 | (void *)BPF_FUNC_get_current_pid_tgid; 35 | static unsigned long long (*bpf_get_current_uid_gid)(void) = 36 | (void *)BPF_FUNC_get_current_uid_gid; 37 | static int (*bpf_get_current_comm)(void *buf, int buf_size) = 38 | (void *)BPF_FUNC_get_current_comm; 39 | static int (*bpf_perf_event_read)(void *map, int index) = 40 | (void *)BPF_FUNC_perf_event_read; 41 | static int (*bpf_clone_redirect)(void *ctx, int ifindex, int flags) = 42 | (void *)BPF_FUNC_clone_redirect; 43 | static int (*bpf_redirect)(int ifindex, int flags) = 44 | (void *)BPF_FUNC_redirect; 45 | static int (*bpf_perf_event_output)(void *ctx, void *map, 46 | unsigned long long flags, void *data, 47 | int size) = 48 | (void *)BPF_FUNC_perf_event_output; 49 | static int (*bpf_skb_get_tunnel_key)(void *ctx, void *key, int size, int flags) = 50 | (void *)BPF_FUNC_skb_get_tunnel_key; 51 | static int (*bpf_skb_set_tunnel_key)(void *ctx, void *key, int size, int flags) = 52 | (void *)BPF_FUNC_skb_set_tunnel_key; 53 | static unsigned long long (*bpf_get_prandom_u32)(void) = 54 | (void *)BPF_FUNC_get_prandom_u32; 55 | 56 | /* llvm builtin functions that eBPF C program may use to 57 | * emit BPF_LD_ABS and BPF_LD_IND instructions 58 | */ 59 | struct sk_buff; 60 | unsigned long long load_byte(void *skb, 61 | unsigned long long off) asm("llvm.bpf.load.byte"); 62 | unsigned long long load_half(void *skb, 63 | unsigned long long off) asm("llvm.bpf.load.half"); 64 | unsigned long long load_word(void *skb, 65 | unsigned long long off) asm("llvm.bpf.load.word"); 66 | 67 | /* a helper structure used by eBPF C program 68 | * to describe map attributes to elf_bpf loader 69 | */ 70 | #define BUF_SIZE_MAP_NS 256 71 | 72 | // struct bpf_map_def 73 | // { 74 | // unsigned int type; 75 | // unsigned int key_size; 76 | // unsigned int value_size; 77 | // unsigned int max_entries; 78 | // unsigned int map_flags; 79 | // unsigned int pinning; 80 | // char namespace[BUF_SIZE_MAP_NS]; 81 | // }; 82 | 83 | static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = 84 | (void *)BPF_FUNC_skb_store_bytes; 85 | static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) = 86 | (void *)BPF_FUNC_l3_csum_replace; 87 | static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) = 88 | (void *)BPF_FUNC_l4_csum_replace; 89 | 90 | #if defined(__x86_64__) 91 | 92 | #define PT_REGS_PARM1(x) ((x)->di) 93 | #define PT_REGS_PARM2(x) ((x)->si) 94 | #define PT_REGS_PARM3(x) ((x)->dx) 95 | #define PT_REGS_PARM4(x) ((x)->cx) 96 | #define PT_REGS_PARM5(x) ((x)->r8) 97 | #define PT_REGS_RET(x) ((x)->sp) 98 | #define PT_REGS_FP(x) ((x)->bp) 99 | #define PT_REGS_RC(x) ((x)->ax) 100 | #define PT_REGS_SP(x) ((x)->sp) 101 | #define PT_REGS_IP(x) ((x)->ip) 102 | 103 | #elif defined(__s390x__) 104 | 105 | #define PT_REGS_PARM1(x) ((x)->gprs[2]) 106 | #define PT_REGS_PARM2(x) ((x)->gprs[3]) 107 | #define PT_REGS_PARM3(x) ((x)->gprs[4]) 108 | #define PT_REGS_PARM4(x) ((x)->gprs[5]) 109 | #define PT_REGS_PARM5(x) ((x)->gprs[6]) 110 | #define PT_REGS_RET(x) ((x)->gprs[14]) 111 | #define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */ 112 | #define PT_REGS_RC(x) ((x)->gprs[2]) 113 | #define PT_REGS_SP(x) ((x)->gprs[15]) 114 | #define PT_REGS_IP(x) ((x)->ip) 115 | 116 | #elif defined(__aarch64__) 117 | 118 | #define PT_REGS_PARM1(x) ((x)->regs[0]) 119 | #define PT_REGS_PARM2(x) ((x)->regs[1]) 120 | #define PT_REGS_PARM3(x) ((x)->regs[2]) 121 | #define PT_REGS_PARM4(x) ((x)->regs[3]) 122 | #define PT_REGS_PARM5(x) ((x)->regs[4]) 123 | #define PT_REGS_RET(x) ((x)->regs[30]) 124 | #define PT_REGS_FP(x) ((x)->regs[29]) /* Works only with CONFIG_FRAME_POINTER */ 125 | #define PT_REGS_RC(x) ((x)->regs[0]) 126 | #define PT_REGS_SP(x) ((x)->sp) 127 | #define PT_REGS_IP(x) ((x)->pc) 128 | 129 | #elif defined(__powerpc__) 130 | 131 | #define PT_REGS_PARM1(x) ((x)->gpr[3]) 132 | #define PT_REGS_PARM2(x) ((x)->gpr[4]) 133 | #define PT_REGS_PARM3(x) ((x)->gpr[5]) 134 | #define PT_REGS_PARM4(x) ((x)->gpr[6]) 135 | #define PT_REGS_PARM5(x) ((x)->gpr[7]) 136 | #define PT_REGS_RC(x) ((x)->gpr[3]) 137 | #define PT_REGS_SP(x) ((x)->sp) 138 | #define PT_REGS_IP(x) ((x)->nip) 139 | 140 | #endif 141 | 142 | #ifdef __powerpc__ 143 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) 144 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP 145 | #else 146 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) 147 | #define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), \ 148 | (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) 149 | #endif 150 | 151 | #endif 152 | -------------------------------------------------------------------------------- /examples/programs/socket/ebpf/main.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_helpers.h" 3 | 4 | SEC("socket/sock_filter") 5 | int socket_sock_filter(void *ctx) 6 | { 7 | bpf_printk("new packet received\n"); 8 | return 0; 9 | }; 10 | 11 | char _license[] SEC("license") = "GPL"; 12 | __u32 _version SEC("version") = 0xFFFFFFFE; 13 | -------------------------------------------------------------------------------- /examples/programs/socket/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/sirupsen/logrus" 5 | 6 | "github.com/gojue/ebpfmanager" 7 | ) 8 | 9 | var m = &manager.Manager{ 10 | Probes: []*manager.Probe{ 11 | { 12 | Section: "socket/sock_filter", 13 | EbpfFuncName: "socket_sock_filter", 14 | }, 15 | }, 16 | } 17 | 18 | func main() { 19 | // Create a socket pair that will be used to trigger the socket filter 20 | sockPair, err := newSocketPair() 21 | if err != nil { 22 | logrus.Fatal(err) 23 | } 24 | 25 | // Set the socket file descriptor on which the socket filter should trigger 26 | m.Probes[0].SocketFD = sockPair[0] 27 | 28 | // Initialize the manager 29 | if err := m.Init(recoverAssets()); err != nil { 30 | logrus.Fatal(err) 31 | } 32 | 33 | // Start the manager 34 | if err := m.Start(); err != nil { 35 | logrus.Fatal(err) 36 | } 37 | 38 | logrus.Println("successfully started, head over to /sys/kernel/debug/tracing/trace_pipe") 39 | 40 | // Send a message through the socket pair to trigger the probe 41 | if err := trigger(sockPair); err != nil { 42 | logrus.Error(err) 43 | } 44 | 45 | // Close the manager 46 | if err := m.Stop(manager.CleanAll); err != nil { 47 | logrus.Fatal(err) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /examples/programs/socket/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "syscall" 8 | 9 | "errors" 10 | "github.com/sirupsen/logrus" 11 | ) 12 | 13 | // recoverAssets - Recover ebpf asset 14 | func recoverAssets() io.ReaderAt { 15 | buf, err := Asset("/probe.o") 16 | if err != nil { 17 | logrus.Fatal(errors.New(fmt.Sprintf("error:%v , couldn't find asset", err))) 18 | } 19 | return bytes.NewReader(buf) 20 | } 21 | 22 | // trigger - Send a message through the socket pair to trigger the probe 23 | func trigger(sockPair SocketPair) error { 24 | logrus.Println("Sending a message through the socket pair to trigger the probes ...") 25 | _, err := syscall.Write(sockPair[1], nil) 26 | if err != nil { 27 | return err 28 | } 29 | _, err = syscall.Read(sockPair[0], nil) 30 | return err 31 | } 32 | 33 | type SocketPair [2]int 34 | 35 | func (p SocketPair) Close() error { 36 | err1 := syscall.Close(p[0]) 37 | err2 := syscall.Close(p[1]) 38 | 39 | if err1 != nil { 40 | return err1 41 | } 42 | return err2 43 | } 44 | 45 | // newSocketPair - Create a socket pair 46 | func newSocketPair() (SocketPair, error) { 47 | return syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0) 48 | } 49 | -------------------------------------------------------------------------------- /examples/programs/sockops/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | ebpf/bin/ 3 | -------------------------------------------------------------------------------- /examples/programs/sockops/Makefile: -------------------------------------------------------------------------------- 1 | all: build-ebpf build run 2 | 3 | build-ebpf: 4 | mkdir -p ebpf/bin 5 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 6 | -Wno-unused-value \ 7 | -Wno-pointer-sign \ 8 | -Wno-compare-distinct-pointer-types \ 9 | -Wunused \ 10 | -Wall \ 11 | -Werror \ 12 | -I/lib/modules/$$(uname -r)/build/include \ 13 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 14 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 15 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 16 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 17 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 18 | -O2 -emit-llvm \ 19 | ebpf/main.c \ 20 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe.o 21 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg main -prefix "ebpf/bin" -o "probe.go" "ebpf/bin/probe.o" 22 | 23 | build: 24 | go build -o bin/main . 25 | 26 | run: 27 | sudo bin/main 28 | -------------------------------------------------------------------------------- /examples/programs/sockops/ebpf/include/bpf_helpers.h: -------------------------------------------------------------------------------- 1 | #ifndef __BPF_HELPERS_H 2 | #define __BPF_HELPERS_H 3 | 4 | #define bpf_printk(fmt, ...) \ 5 | ({ \ 6 | char ____fmt[] = fmt; \ 7 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 8 | ##__VA_ARGS__); \ 9 | }) 10 | 11 | /* helper macro to place programs, maps, license in 12 | * different sections in elf_bpf file. Section names 13 | * are interpreted by elf_bpf loader 14 | */ 15 | #define SEC(NAME) __attribute__((section(NAME), used)) 16 | 17 | /* helper functions called from eBPF programs written in C */ 18 | static void *(*bpf_map_lookup_elem)(void *map, void *key) = 19 | (void *)BPF_FUNC_map_lookup_elem; 20 | static int (*bpf_map_update_elem)(void *map, void *key, void *value, 21 | unsigned long long flags) = 22 | (void *)BPF_FUNC_map_update_elem; 23 | static int (*bpf_map_delete_elem)(void *map, void *key) = 24 | (void *)BPF_FUNC_map_delete_elem; 25 | static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) = 26 | (void *)BPF_FUNC_probe_read; 27 | static unsigned long long (*bpf_ktime_get_ns)(void) = 28 | (void *)BPF_FUNC_ktime_get_ns; 29 | static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = 30 | (void *)BPF_FUNC_trace_printk; 31 | static unsigned long long (*bpf_get_smp_processor_id)(void) = 32 | (void *)BPF_FUNC_get_smp_processor_id; 33 | static unsigned long long (*bpf_get_current_pid_tgid)(void) = 34 | (void *)BPF_FUNC_get_current_pid_tgid; 35 | static unsigned long long (*bpf_get_current_uid_gid)(void) = 36 | (void *)BPF_FUNC_get_current_uid_gid; 37 | static int (*bpf_get_current_comm)(void *buf, int buf_size) = 38 | (void *)BPF_FUNC_get_current_comm; 39 | static int (*bpf_perf_event_read)(void *map, int index) = 40 | (void *)BPF_FUNC_perf_event_read; 41 | static int (*bpf_clone_redirect)(void *ctx, int ifindex, int flags) = 42 | (void *)BPF_FUNC_clone_redirect; 43 | static int (*bpf_redirect)(int ifindex, int flags) = 44 | (void *)BPF_FUNC_redirect; 45 | static int (*bpf_perf_event_output)(void *ctx, void *map, 46 | unsigned long long flags, void *data, 47 | int size) = 48 | (void *)BPF_FUNC_perf_event_output; 49 | static int (*bpf_skb_get_tunnel_key)(void *ctx, void *key, int size, int flags) = 50 | (void *)BPF_FUNC_skb_get_tunnel_key; 51 | static int (*bpf_skb_set_tunnel_key)(void *ctx, void *key, int size, int flags) = 52 | (void *)BPF_FUNC_skb_set_tunnel_key; 53 | static unsigned long long (*bpf_get_prandom_u32)(void) = 54 | (void *)BPF_FUNC_get_prandom_u32; 55 | 56 | /* llvm builtin functions that eBPF C program may use to 57 | * emit BPF_LD_ABS and BPF_LD_IND instructions 58 | */ 59 | struct sk_buff; 60 | unsigned long long load_byte(void *skb, 61 | unsigned long long off) asm("llvm.bpf.load.byte"); 62 | unsigned long long load_half(void *skb, 63 | unsigned long long off) asm("llvm.bpf.load.half"); 64 | unsigned long long load_word(void *skb, 65 | unsigned long long off) asm("llvm.bpf.load.word"); 66 | 67 | /* a helper structure used by eBPF C program 68 | * to describe map attributes to elf_bpf loader 69 | */ 70 | #define BUF_SIZE_MAP_NS 256 71 | 72 | // struct bpf_map_def 73 | // { 74 | // unsigned int type; 75 | // unsigned int key_size; 76 | // unsigned int value_size; 77 | // unsigned int max_entries; 78 | // unsigned int map_flags; 79 | // unsigned int pinning; 80 | // char namespace[BUF_SIZE_MAP_NS]; 81 | // }; 82 | 83 | static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = 84 | (void *)BPF_FUNC_skb_store_bytes; 85 | static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) = 86 | (void *)BPF_FUNC_l3_csum_replace; 87 | static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) = 88 | (void *)BPF_FUNC_l4_csum_replace; 89 | 90 | #if defined(__x86_64__) 91 | 92 | #define PT_REGS_PARM1(x) ((x)->di) 93 | #define PT_REGS_PARM2(x) ((x)->si) 94 | #define PT_REGS_PARM3(x) ((x)->dx) 95 | #define PT_REGS_PARM4(x) ((x)->cx) 96 | #define PT_REGS_PARM5(x) ((x)->r8) 97 | #define PT_REGS_RET(x) ((x)->sp) 98 | #define PT_REGS_FP(x) ((x)->bp) 99 | #define PT_REGS_RC(x) ((x)->ax) 100 | #define PT_REGS_SP(x) ((x)->sp) 101 | #define PT_REGS_IP(x) ((x)->ip) 102 | 103 | #elif defined(__s390x__) 104 | 105 | #define PT_REGS_PARM1(x) ((x)->gprs[2]) 106 | #define PT_REGS_PARM2(x) ((x)->gprs[3]) 107 | #define PT_REGS_PARM3(x) ((x)->gprs[4]) 108 | #define PT_REGS_PARM4(x) ((x)->gprs[5]) 109 | #define PT_REGS_PARM5(x) ((x)->gprs[6]) 110 | #define PT_REGS_RET(x) ((x)->gprs[14]) 111 | #define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */ 112 | #define PT_REGS_RC(x) ((x)->gprs[2]) 113 | #define PT_REGS_SP(x) ((x)->gprs[15]) 114 | #define PT_REGS_IP(x) ((x)->ip) 115 | 116 | #elif defined(__aarch64__) 117 | 118 | #define PT_REGS_PARM1(x) ((x)->regs[0]) 119 | #define PT_REGS_PARM2(x) ((x)->regs[1]) 120 | #define PT_REGS_PARM3(x) ((x)->regs[2]) 121 | #define PT_REGS_PARM4(x) ((x)->regs[3]) 122 | #define PT_REGS_PARM5(x) ((x)->regs[4]) 123 | #define PT_REGS_RET(x) ((x)->regs[30]) 124 | #define PT_REGS_FP(x) ((x)->regs[29]) /* Works only with CONFIG_FRAME_POINTER */ 125 | #define PT_REGS_RC(x) ((x)->regs[0]) 126 | #define PT_REGS_SP(x) ((x)->sp) 127 | #define PT_REGS_IP(x) ((x)->pc) 128 | 129 | #elif defined(__powerpc__) 130 | 131 | #define PT_REGS_PARM1(x) ((x)->gpr[3]) 132 | #define PT_REGS_PARM2(x) ((x)->gpr[4]) 133 | #define PT_REGS_PARM3(x) ((x)->gpr[5]) 134 | #define PT_REGS_PARM4(x) ((x)->gpr[6]) 135 | #define PT_REGS_PARM5(x) ((x)->gpr[7]) 136 | #define PT_REGS_RC(x) ((x)->gpr[3]) 137 | #define PT_REGS_SP(x) ((x)->sp) 138 | #define PT_REGS_IP(x) ((x)->nip) 139 | 140 | #endif 141 | 142 | #ifdef __powerpc__ 143 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) 144 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP 145 | #else 146 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) 147 | #define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), \ 148 | (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) 149 | #endif 150 | 151 | #endif 152 | -------------------------------------------------------------------------------- /examples/programs/sockops/ebpf/main.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_helpers.h" 3 | 4 | SEC("sockops") 5 | int bpf_sockops(struct bpf_sock_ops *skops) 6 | { 7 | switch (skops->op) { 8 | default: 9 | bpf_printk("eBPF sockops : %d \n",skops->op); 10 | } 11 | return 0; 12 | } 13 | char _license[] SEC("license") = "GPL"; 14 | __u32 _version SEC("version") = 0xFFFFFFFE; 15 | -------------------------------------------------------------------------------- /examples/programs/sockops/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "github.com/gojue/ebpfmanager" 7 | "github.com/sirupsen/logrus" 8 | "os" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | var m = &manager.Manager{ 14 | Probes: []*manager.Probe{ 15 | { 16 | EbpfFuncName: "bpf_sockops", 17 | Section: "sockops", 18 | }, 19 | }, 20 | } 21 | 22 | func main() { 23 | cp, err := detectCgroupPath() 24 | if err != nil { 25 | logrus.Fatal(err) 26 | } 27 | m.Probes[0].CGroupPath = cp 28 | 29 | logrus.Println("try to attach sockops ebpf programs.") 30 | // Initialize the manager 31 | if err := m.Init(recoverAssets()); err != nil { 32 | logrus.Fatal(err) 33 | } 34 | 35 | // Start the manager 36 | if err := m.Start(); err != nil { 37 | logrus.Fatal(err) 38 | } 39 | 40 | logrus.Println("successfully started, head over to /sys/kernel/debug/tracing/trace_pipe") 41 | time.Sleep(time.Second * 3) 42 | // Generate some network traffic to trigger the probe 43 | trigger() 44 | 45 | // Close the manager 46 | if err := m.Stop(manager.CleanAll); err != nil { 47 | logrus.Fatal(err) 48 | } 49 | } 50 | 51 | func detectCgroupPath() (string, error) { 52 | f, err := os.Open("/proc/mounts") 53 | if err != nil { 54 | return "", err 55 | } 56 | defer f.Close() 57 | 58 | scanner := bufio.NewScanner(f) 59 | for scanner.Scan() { 60 | fields := strings.Split(scanner.Text(), " ") 61 | if len(fields) >= 3 && fields[2] == "cgroup2" { 62 | return fields[1], nil 63 | } 64 | } 65 | 66 | return "", errors.New("cgroup2 is not mounted") 67 | } 68 | -------------------------------------------------------------------------------- /examples/programs/sockops/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "github.com/sirupsen/logrus" 8 | "io" 9 | "net/http" 10 | ) 11 | 12 | // recoverAssets - Recover ebpf asset 13 | func recoverAssets() io.ReaderAt { 14 | buf, err := Asset("/probe.o") 15 | if err != nil { 16 | logrus.Fatal(errors.New(fmt.Sprintf("error:%v , couldn't find asset", err))) 17 | } 18 | return bytes.NewReader(buf) 19 | } 20 | 21 | // trigger - Generate some network traffic to trigger the probe 22 | func trigger() { 23 | logrus.Println("Generating some network traffic to trigger the probes ...") 24 | _, _ = http.Get("https://www.bing.com/") 25 | } 26 | -------------------------------------------------------------------------------- /examples/programs/tc/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | ebpf/bin/ 3 | -------------------------------------------------------------------------------- /examples/programs/tc/Makefile: -------------------------------------------------------------------------------- 1 | all: build-ebpf build run 2 | 3 | build-ebpf: 4 | mkdir -p ebpf/bin 5 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 6 | -Wno-unused-value \ 7 | -Wno-pointer-sign \ 8 | -Wno-compare-distinct-pointer-types \ 9 | -Wunused \ 10 | -Wall \ 11 | -Werror \ 12 | -I/lib/modules/$$(uname -r)/build/include \ 13 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 14 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 15 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 16 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 17 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 18 | -O2 -emit-llvm \ 19 | ebpf/main.c \ 20 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe.o 21 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg main -prefix "ebpf/bin" -o "probe.go" "ebpf/bin/probe.o" 22 | 23 | build: 24 | go build -o bin/main . 25 | 26 | run: 27 | sudo bin/main 28 | -------------------------------------------------------------------------------- /examples/programs/tc/ebpf/include/bpf_helpers.h: -------------------------------------------------------------------------------- 1 | #ifndef __BPF_HELPERS_H 2 | #define __BPF_HELPERS_H 3 | 4 | #define bpf_printk(fmt, ...) \ 5 | ({ \ 6 | char ____fmt[] = fmt; \ 7 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 8 | ##__VA_ARGS__); \ 9 | }) 10 | 11 | /* helper macro to place programs, maps, license in 12 | * different sections in elf_bpf file. Section names 13 | * are interpreted by elf_bpf loader 14 | */ 15 | #define SEC(NAME) __attribute__((section(NAME), used)) 16 | 17 | /* helper functions called from eBPF programs written in C */ 18 | static void *(*bpf_map_lookup_elem)(void *map, void *key) = 19 | (void *)BPF_FUNC_map_lookup_elem; 20 | static int (*bpf_map_update_elem)(void *map, void *key, void *value, 21 | unsigned long long flags) = 22 | (void *)BPF_FUNC_map_update_elem; 23 | static int (*bpf_map_delete_elem)(void *map, void *key) = 24 | (void *)BPF_FUNC_map_delete_elem; 25 | static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) = 26 | (void *)BPF_FUNC_probe_read; 27 | static unsigned long long (*bpf_ktime_get_ns)(void) = 28 | (void *)BPF_FUNC_ktime_get_ns; 29 | static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = 30 | (void *)BPF_FUNC_trace_printk; 31 | static unsigned long long (*bpf_get_smp_processor_id)(void) = 32 | (void *)BPF_FUNC_get_smp_processor_id; 33 | static unsigned long long (*bpf_get_current_pid_tgid)(void) = 34 | (void *)BPF_FUNC_get_current_pid_tgid; 35 | static unsigned long long (*bpf_get_current_uid_gid)(void) = 36 | (void *)BPF_FUNC_get_current_uid_gid; 37 | static int (*bpf_get_current_comm)(void *buf, int buf_size) = 38 | (void *)BPF_FUNC_get_current_comm; 39 | static int (*bpf_perf_event_read)(void *map, int index) = 40 | (void *)BPF_FUNC_perf_event_read; 41 | static int (*bpf_clone_redirect)(void *ctx, int ifindex, int flags) = 42 | (void *)BPF_FUNC_clone_redirect; 43 | static int (*bpf_redirect)(int ifindex, int flags) = 44 | (void *)BPF_FUNC_redirect; 45 | static int (*bpf_perf_event_output)(void *ctx, void *map, 46 | unsigned long long flags, void *data, 47 | int size) = 48 | (void *)BPF_FUNC_perf_event_output; 49 | static int (*bpf_skb_get_tunnel_key)(void *ctx, void *key, int size, int flags) = 50 | (void *)BPF_FUNC_skb_get_tunnel_key; 51 | static int (*bpf_skb_set_tunnel_key)(void *ctx, void *key, int size, int flags) = 52 | (void *)BPF_FUNC_skb_set_tunnel_key; 53 | static unsigned long long (*bpf_get_prandom_u32)(void) = 54 | (void *)BPF_FUNC_get_prandom_u32; 55 | 56 | /* llvm builtin functions that eBPF C program may use to 57 | * emit BPF_LD_ABS and BPF_LD_IND instructions 58 | */ 59 | struct sk_buff; 60 | unsigned long long load_byte(void *skb, 61 | unsigned long long off) asm("llvm.bpf.load.byte"); 62 | unsigned long long load_half(void *skb, 63 | unsigned long long off) asm("llvm.bpf.load.half"); 64 | unsigned long long load_word(void *skb, 65 | unsigned long long off) asm("llvm.bpf.load.word"); 66 | 67 | /* a helper structure used by eBPF C program 68 | * to describe map attributes to elf_bpf loader 69 | */ 70 | #define BUF_SIZE_MAP_NS 256 71 | 72 | // struct bpf_map_def 73 | // { 74 | // unsigned int type; 75 | // unsigned int key_size; 76 | // unsigned int value_size; 77 | // unsigned int max_entries; 78 | // unsigned int map_flags; 79 | // unsigned int pinning; 80 | // char namespace[BUF_SIZE_MAP_NS]; 81 | // }; 82 | 83 | static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = 84 | (void *)BPF_FUNC_skb_store_bytes; 85 | static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) = 86 | (void *)BPF_FUNC_l3_csum_replace; 87 | static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) = 88 | (void *)BPF_FUNC_l4_csum_replace; 89 | 90 | #if defined(__x86_64__) 91 | 92 | #define PT_REGS_PARM1(x) ((x)->di) 93 | #define PT_REGS_PARM2(x) ((x)->si) 94 | #define PT_REGS_PARM3(x) ((x)->dx) 95 | #define PT_REGS_PARM4(x) ((x)->cx) 96 | #define PT_REGS_PARM5(x) ((x)->r8) 97 | #define PT_REGS_RET(x) ((x)->sp) 98 | #define PT_REGS_FP(x) ((x)->bp) 99 | #define PT_REGS_RC(x) ((x)->ax) 100 | #define PT_REGS_SP(x) ((x)->sp) 101 | #define PT_REGS_IP(x) ((x)->ip) 102 | 103 | #elif defined(__s390x__) 104 | 105 | #define PT_REGS_PARM1(x) ((x)->gprs[2]) 106 | #define PT_REGS_PARM2(x) ((x)->gprs[3]) 107 | #define PT_REGS_PARM3(x) ((x)->gprs[4]) 108 | #define PT_REGS_PARM4(x) ((x)->gprs[5]) 109 | #define PT_REGS_PARM5(x) ((x)->gprs[6]) 110 | #define PT_REGS_RET(x) ((x)->gprs[14]) 111 | #define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */ 112 | #define PT_REGS_RC(x) ((x)->gprs[2]) 113 | #define PT_REGS_SP(x) ((x)->gprs[15]) 114 | #define PT_REGS_IP(x) ((x)->ip) 115 | 116 | #elif defined(__aarch64__) 117 | 118 | #define PT_REGS_PARM1(x) ((x)->regs[0]) 119 | #define PT_REGS_PARM2(x) ((x)->regs[1]) 120 | #define PT_REGS_PARM3(x) ((x)->regs[2]) 121 | #define PT_REGS_PARM4(x) ((x)->regs[3]) 122 | #define PT_REGS_PARM5(x) ((x)->regs[4]) 123 | #define PT_REGS_RET(x) ((x)->regs[30]) 124 | #define PT_REGS_FP(x) ((x)->regs[29]) /* Works only with CONFIG_FRAME_POINTER */ 125 | #define PT_REGS_RC(x) ((x)->regs[0]) 126 | #define PT_REGS_SP(x) ((x)->sp) 127 | #define PT_REGS_IP(x) ((x)->pc) 128 | 129 | #elif defined(__powerpc__) 130 | 131 | #define PT_REGS_PARM1(x) ((x)->gpr[3]) 132 | #define PT_REGS_PARM2(x) ((x)->gpr[4]) 133 | #define PT_REGS_PARM3(x) ((x)->gpr[5]) 134 | #define PT_REGS_PARM4(x) ((x)->gpr[6]) 135 | #define PT_REGS_PARM5(x) ((x)->gpr[7]) 136 | #define PT_REGS_RC(x) ((x)->gpr[3]) 137 | #define PT_REGS_SP(x) ((x)->sp) 138 | #define PT_REGS_IP(x) ((x)->nip) 139 | 140 | #endif 141 | 142 | #ifdef __powerpc__ 143 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) 144 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP 145 | #else 146 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) 147 | #define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), \ 148 | (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) 149 | #endif 150 | 151 | #endif 152 | -------------------------------------------------------------------------------- /examples/programs/tc/ebpf/main.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_helpers.h" 3 | 4 | #include 5 | 6 | SEC("classifier/egress") 7 | int egress_cls_func(struct __sk_buff *skb) 8 | { 9 | bpf_printk("new packet captured on egress (TC)\n"); 10 | return TC_ACT_OK; 11 | }; 12 | 13 | SEC("classifier/ingress") 14 | int ingress_cls_func(struct __sk_buff *skb) 15 | { 16 | bpf_printk("new packet captured on ingress (TC)\n"); 17 | return TC_ACT_OK; 18 | }; 19 | 20 | char _license[] SEC("license") = "GPL"; 21 | __u32 _version SEC("version") = 0xFFFFFFFE; 22 | -------------------------------------------------------------------------------- /examples/programs/tc/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/gojue/ebpfmanager" 5 | "github.com/sirupsen/logrus" 6 | ) 7 | 8 | var m = &manager.Manager{ 9 | Probes: []*manager.Probe{ 10 | { 11 | Section: "classifier/egress", 12 | EbpfFuncName: "egress_cls_func", 13 | Ifname: "eth0", // change this to the interface connected to the internet 14 | NetworkDirection: manager.Egress, 15 | SkipLoopback: true, 16 | }, 17 | { 18 | Section: "classifier/ingress", 19 | EbpfFuncName: "ingress_cls_func", 20 | Ifname: "eth0", // change this to the interface connected to the internet 21 | NetworkDirection: manager.Ingress, 22 | }, 23 | }, 24 | } 25 | 26 | func main() { 27 | // Initialize the manager 28 | if err := m.Init(recoverAssets()); err != nil { 29 | logrus.Fatal(err) 30 | } 31 | 32 | // Start the manager 33 | if err := m.Start(); err != nil { 34 | logrus.Fatal(err) 35 | } 36 | 37 | logrus.Println("successfully started, head over to /sys/kernel/debug/tracing/trace_pipe") 38 | 39 | // Generate some network traffic to trigger the probe 40 | trigger() 41 | 42 | // Close the manager 43 | if err := m.Stop(manager.CleanAll); err != nil { 44 | logrus.Fatal(err) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/programs/tc/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "github.com/sirupsen/logrus" 8 | "io" 9 | "net/http" 10 | ) 11 | 12 | // recoverAssets - Recover ebpf asset 13 | func recoverAssets() io.ReaderAt { 14 | buf, err := Asset("/probe.o") 15 | if err != nil { 16 | logrus.Fatal(errors.New(fmt.Sprintf("error:%v , couldn't find asset", err))) 17 | } 18 | return bytes.NewReader(buf) 19 | } 20 | 21 | // trigger - Generate some network traffic to trigger the probe 22 | func trigger() { 23 | logrus.Println("Generating some network traffic to trigger the probes ...") 24 | _, _ = http.Get("https://www.google.com/") 25 | } 26 | -------------------------------------------------------------------------------- /examples/programs/tracepoint/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | ebpf/bin/ 3 | -------------------------------------------------------------------------------- /examples/programs/tracepoint/Makefile: -------------------------------------------------------------------------------- 1 | all: build-ebpf build run 2 | 3 | build-ebpf: 4 | mkdir -p ebpf/bin 5 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 6 | -Wno-unused-value \ 7 | -Wno-pointer-sign \ 8 | -Wno-compare-distinct-pointer-types \ 9 | -Wunused \ 10 | -Wall \ 11 | -Werror \ 12 | -I/lib/modules/$$(uname -r)/build/include \ 13 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 14 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 15 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 16 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 17 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 18 | -O2 -emit-llvm \ 19 | ebpf/main.c \ 20 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe.o 21 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg main -prefix "ebpf/bin" -o "probe.go" "ebpf/bin/probe.o" 22 | 23 | build: 24 | go build -o bin/main . 25 | 26 | run: 27 | sudo bin/main 28 | -------------------------------------------------------------------------------- /examples/programs/tracepoint/ebpf/main.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_helpers.h" 3 | 4 | SEC("tracepoint/syscalls/sys_enter_mkdirat") 5 | int tracepoint_sys_enter_mkdirat(void *ctx) 6 | { 7 | bpf_printk("mkdirat enter (tracepoint)\n"); 8 | return 0; 9 | }; 10 | 11 | char _license[] SEC("license") = "GPL"; 12 | __u32 _version SEC("version") = 0xFFFFFFFE; 13 | -------------------------------------------------------------------------------- /examples/programs/tracepoint/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/sirupsen/logrus" 5 | 6 | "github.com/gojue/ebpfmanager" 7 | ) 8 | 9 | var m = &manager.Manager{ 10 | Probes: []*manager.Probe{ 11 | { 12 | Section: "tracepoint/syscalls/sys_enter_mkdirat", 13 | EbpfFuncName: "tracepoint_sys_enter_mkdirat", 14 | }, 15 | }, 16 | } 17 | 18 | func main() { 19 | // Initialize the manager 20 | if err := m.Init(recoverAssets()); err != nil { 21 | logrus.Fatal(err) 22 | } 23 | 24 | // Start the manager 25 | if err := m.Start(); err != nil { 26 | logrus.Fatal(err) 27 | } 28 | 29 | logrus.Println("successfully started, head over to /sys/kernel/debug/tracing/trace_pipe") 30 | 31 | // Create a folder to trigger the probes 32 | if err := trigger(); err != nil { 33 | logrus.Error(err) 34 | } 35 | 36 | // Close the manager 37 | if err := m.Stop(manager.CleanAll); err != nil { 38 | logrus.Fatal(err) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/programs/tracepoint/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "os" 8 | 9 | "errors" 10 | "github.com/sirupsen/logrus" 11 | ) 12 | 13 | // recoverAssets - Recover ebpf asset 14 | func recoverAssets() io.ReaderAt { 15 | buf, err := Asset("/probe.o") 16 | if err != nil { 17 | logrus.Fatal(errors.New(fmt.Sprintf("error:%v , couldn't find asset", err))) 18 | } 19 | return bytes.NewReader(buf) 20 | } 21 | 22 | // trigger - Creates and then removes a tmp folder to trigger the probes 23 | func trigger() error { 24 | logrus.Println("Generating events to trigger the probes ...") 25 | // Creating a tmp directory to trigger the probes 26 | tmpDir := "/tmp/test_folder" 27 | logrus.Printf("creating %v", tmpDir) 28 | err := os.MkdirAll(tmpDir, 0666) 29 | if err != nil { 30 | return err 31 | } 32 | 33 | // Removing a tmp directory to trigger the probes 34 | logrus.Printf("removing %v", tmpDir) 35 | return os.RemoveAll(tmpDir) 36 | } 37 | 38 | -------------------------------------------------------------------------------- /examples/programs/uprobe/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | ebpf/bin/ 3 | -------------------------------------------------------------------------------- /examples/programs/uprobe/Makefile: -------------------------------------------------------------------------------- 1 | all: build-ebpf build run 2 | 3 | build-ebpf: 4 | mkdir -p ebpf/bin 5 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 6 | -Wno-unused-value \ 7 | -Wno-pointer-sign \ 8 | -Wno-compare-distinct-pointer-types \ 9 | -Wunused \ 10 | -Wall \ 11 | -Werror \ 12 | -I/lib/modules/$$(uname -r)/build/include \ 13 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 14 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 15 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 16 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 17 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 18 | -O2 -emit-llvm \ 19 | ebpf/main.c \ 20 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe.o 21 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg main -prefix "ebpf/bin" -o "probe.go" "ebpf/bin/probe.o" 22 | 23 | build: 24 | go build -o bin/main . 25 | 26 | run: 27 | sudo bin/main 28 | -------------------------------------------------------------------------------- /examples/programs/uprobe/ebpf/main.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_helpers.h" 3 | 4 | SEC("uprobe/readline") 5 | int uprobe_readline(void *ctx) 6 | { 7 | bpf_printk("new bash command detected\n"); 8 | return 0; 9 | }; 10 | 11 | char _license[] SEC("license") = "GPL"; 12 | __u32 _version SEC("version") = 0xFFFFFFFE; 13 | -------------------------------------------------------------------------------- /examples/programs/uprobe/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/gojue/ebpfmanager" 5 | "github.com/sirupsen/logrus" 6 | ) 7 | 8 | var m = &manager.Manager{ 9 | Probes: []*manager.Probe{ 10 | { 11 | Section: "uprobe/readline", 12 | EbpfFuncName: "uprobe_readline", 13 | AttachToFuncName: "readline", 14 | BinaryPath: "/usr/bin/bash", 15 | }, 16 | }, 17 | } 18 | 19 | func main() { 20 | // Initialize the manager 21 | if err := m.Init(recoverAssets()); err != nil { 22 | logrus.Fatal(err) 23 | } 24 | 25 | // Start the manager 26 | if err := m.Start(); err != nil { 27 | logrus.Fatal(err) 28 | } 29 | 30 | logrus.Println("successfully started, head over to /sys/kernel/debug/tracing/trace_pipe") 31 | 32 | // Spawn a bash and right a command to trigger the probe 33 | if err := trigger(); err != nil { 34 | logrus.Error(err) 35 | } 36 | 37 | // Close the manager 38 | if err := m.Stop(manager.CleanAll); err != nil { 39 | logrus.Fatal(err) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /examples/programs/uprobe/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "os/exec" 8 | "time" 9 | 10 | "errors" 11 | "github.com/sirupsen/logrus" 12 | ) 13 | 14 | // recoverAssets - Recover ebpf asset 15 | func recoverAssets() io.ReaderAt { 16 | buf, err := Asset("/probe.o") 17 | if err != nil { 18 | logrus.Fatal(errors.New(fmt.Sprintf("error:%v , couldn't find asset", err))) 19 | } 20 | return bytes.NewReader(buf) 21 | } 22 | 23 | // trigger - Spawn a bash and execute a command to trigger the probe 24 | func trigger() error { 25 | logrus.Println("Spawning a shell and executing `id` to trigger the probe ...") 26 | cmd := exec.Command("/usr/bin/bash", "-i") 27 | stdinPipe, _ := cmd.StdinPipe() 28 | go func() { 29 | io.WriteString(stdinPipe, "id") 30 | time.Sleep(100*time.Millisecond) 31 | stdinPipe.Close() 32 | }() 33 | b, err := cmd.Output() 34 | if err != nil { 35 | return err 36 | } 37 | logrus.Printf("from bash: %v", string(b)) 38 | return nil 39 | } 40 | 41 | -------------------------------------------------------------------------------- /examples/programs/xdp/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | ebpf/bin/ 3 | -------------------------------------------------------------------------------- /examples/programs/xdp/Makefile: -------------------------------------------------------------------------------- 1 | all: build-ebpf build run 2 | 3 | build-ebpf: 4 | mkdir -p ebpf/bin 5 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 6 | -Wno-unused-value \ 7 | -Wno-pointer-sign \ 8 | -Wno-compare-distinct-pointer-types \ 9 | -Wunused \ 10 | -Wall \ 11 | -Werror \ 12 | -I/lib/modules/$$(uname -r)/build/include \ 13 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 14 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 15 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 16 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 17 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 18 | -O2 -emit-llvm \ 19 | ebpf/main.c \ 20 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe.o 21 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg main -prefix "ebpf/bin" -o "probe.go" "ebpf/bin/probe.o" 22 | 23 | build: 24 | go build -o bin/main . 25 | 26 | run: 27 | sudo bin/main 28 | -------------------------------------------------------------------------------- /examples/programs/xdp/ebpf/include/bpf_helpers.h: -------------------------------------------------------------------------------- 1 | #ifndef __BPF_HELPERS_H 2 | #define __BPF_HELPERS_H 3 | 4 | #define bpf_printk(fmt, ...) \ 5 | ({ \ 6 | char ____fmt[] = fmt; \ 7 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 8 | ##__VA_ARGS__); \ 9 | }) 10 | 11 | /* helper macro to place programs, maps, license in 12 | * different sections in elf_bpf file. Section names 13 | * are interpreted by elf_bpf loader 14 | */ 15 | #define SEC(NAME) __attribute__((section(NAME), used)) 16 | 17 | /* helper functions called from eBPF programs written in C */ 18 | static void *(*bpf_map_lookup_elem)(void *map, void *key) = 19 | (void *)BPF_FUNC_map_lookup_elem; 20 | static int (*bpf_map_update_elem)(void *map, void *key, void *value, 21 | unsigned long long flags) = 22 | (void *)BPF_FUNC_map_update_elem; 23 | static int (*bpf_map_delete_elem)(void *map, void *key) = 24 | (void *)BPF_FUNC_map_delete_elem; 25 | static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) = 26 | (void *)BPF_FUNC_probe_read; 27 | static unsigned long long (*bpf_ktime_get_ns)(void) = 28 | (void *)BPF_FUNC_ktime_get_ns; 29 | static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = 30 | (void *)BPF_FUNC_trace_printk; 31 | static unsigned long long (*bpf_get_smp_processor_id)(void) = 32 | (void *)BPF_FUNC_get_smp_processor_id; 33 | static unsigned long long (*bpf_get_current_pid_tgid)(void) = 34 | (void *)BPF_FUNC_get_current_pid_tgid; 35 | static unsigned long long (*bpf_get_current_uid_gid)(void) = 36 | (void *)BPF_FUNC_get_current_uid_gid; 37 | static int (*bpf_get_current_comm)(void *buf, int buf_size) = 38 | (void *)BPF_FUNC_get_current_comm; 39 | static int (*bpf_perf_event_read)(void *map, int index) = 40 | (void *)BPF_FUNC_perf_event_read; 41 | static int (*bpf_clone_redirect)(void *ctx, int ifindex, int flags) = 42 | (void *)BPF_FUNC_clone_redirect; 43 | static int (*bpf_redirect)(int ifindex, int flags) = 44 | (void *)BPF_FUNC_redirect; 45 | static int (*bpf_perf_event_output)(void *ctx, void *map, 46 | unsigned long long flags, void *data, 47 | int size) = 48 | (void *)BPF_FUNC_perf_event_output; 49 | static int (*bpf_skb_get_tunnel_key)(void *ctx, void *key, int size, int flags) = 50 | (void *)BPF_FUNC_skb_get_tunnel_key; 51 | static int (*bpf_skb_set_tunnel_key)(void *ctx, void *key, int size, int flags) = 52 | (void *)BPF_FUNC_skb_set_tunnel_key; 53 | static unsigned long long (*bpf_get_prandom_u32)(void) = 54 | (void *)BPF_FUNC_get_prandom_u32; 55 | 56 | /* llvm builtin functions that eBPF C program may use to 57 | * emit BPF_LD_ABS and BPF_LD_IND instructions 58 | */ 59 | struct sk_buff; 60 | unsigned long long load_byte(void *skb, 61 | unsigned long long off) asm("llvm.bpf.load.byte"); 62 | unsigned long long load_half(void *skb, 63 | unsigned long long off) asm("llvm.bpf.load.half"); 64 | unsigned long long load_word(void *skb, 65 | unsigned long long off) asm("llvm.bpf.load.word"); 66 | 67 | /* a helper structure used by eBPF C program 68 | * to describe map attributes to elf_bpf loader 69 | */ 70 | #define BUF_SIZE_MAP_NS 256 71 | 72 | // struct bpf_map_def 73 | // { 74 | // unsigned int type; 75 | // unsigned int key_size; 76 | // unsigned int value_size; 77 | // unsigned int max_entries; 78 | // unsigned int map_flags; 79 | // unsigned int pinning; 80 | // char namespace[BUF_SIZE_MAP_NS]; 81 | // }; 82 | 83 | static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = 84 | (void *)BPF_FUNC_skb_store_bytes; 85 | static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) = 86 | (void *)BPF_FUNC_l3_csum_replace; 87 | static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) = 88 | (void *)BPF_FUNC_l4_csum_replace; 89 | 90 | #if defined(__x86_64__) 91 | 92 | #define PT_REGS_PARM1(x) ((x)->di) 93 | #define PT_REGS_PARM2(x) ((x)->si) 94 | #define PT_REGS_PARM3(x) ((x)->dx) 95 | #define PT_REGS_PARM4(x) ((x)->cx) 96 | #define PT_REGS_PARM5(x) ((x)->r8) 97 | #define PT_REGS_RET(x) ((x)->sp) 98 | #define PT_REGS_FP(x) ((x)->bp) 99 | #define PT_REGS_RC(x) ((x)->ax) 100 | #define PT_REGS_SP(x) ((x)->sp) 101 | #define PT_REGS_IP(x) ((x)->ip) 102 | 103 | #elif defined(__s390x__) 104 | 105 | #define PT_REGS_PARM1(x) ((x)->gprs[2]) 106 | #define PT_REGS_PARM2(x) ((x)->gprs[3]) 107 | #define PT_REGS_PARM3(x) ((x)->gprs[4]) 108 | #define PT_REGS_PARM4(x) ((x)->gprs[5]) 109 | #define PT_REGS_PARM5(x) ((x)->gprs[6]) 110 | #define PT_REGS_RET(x) ((x)->gprs[14]) 111 | #define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */ 112 | #define PT_REGS_RC(x) ((x)->gprs[2]) 113 | #define PT_REGS_SP(x) ((x)->gprs[15]) 114 | #define PT_REGS_IP(x) ((x)->ip) 115 | 116 | #elif defined(__aarch64__) 117 | 118 | #define PT_REGS_PARM1(x) ((x)->regs[0]) 119 | #define PT_REGS_PARM2(x) ((x)->regs[1]) 120 | #define PT_REGS_PARM3(x) ((x)->regs[2]) 121 | #define PT_REGS_PARM4(x) ((x)->regs[3]) 122 | #define PT_REGS_PARM5(x) ((x)->regs[4]) 123 | #define PT_REGS_RET(x) ((x)->regs[30]) 124 | #define PT_REGS_FP(x) ((x)->regs[29]) /* Works only with CONFIG_FRAME_POINTER */ 125 | #define PT_REGS_RC(x) ((x)->regs[0]) 126 | #define PT_REGS_SP(x) ((x)->sp) 127 | #define PT_REGS_IP(x) ((x)->pc) 128 | 129 | #elif defined(__powerpc__) 130 | 131 | #define PT_REGS_PARM1(x) ((x)->gpr[3]) 132 | #define PT_REGS_PARM2(x) ((x)->gpr[4]) 133 | #define PT_REGS_PARM3(x) ((x)->gpr[5]) 134 | #define PT_REGS_PARM4(x) ((x)->gpr[6]) 135 | #define PT_REGS_PARM5(x) ((x)->gpr[7]) 136 | #define PT_REGS_RC(x) ((x)->gpr[3]) 137 | #define PT_REGS_SP(x) ((x)->sp) 138 | #define PT_REGS_IP(x) ((x)->nip) 139 | 140 | #endif 141 | 142 | #ifdef __powerpc__ 143 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) 144 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP 145 | #else 146 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) 147 | #define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ bpf_probe_read(&(ip), sizeof(ip), \ 148 | (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) 149 | #endif 150 | 151 | #endif 152 | -------------------------------------------------------------------------------- /examples/programs/xdp/ebpf/main.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_helpers.h" 3 | 4 | SEC("xdp/ingress") 5 | int egress_cls_func(struct __sk_buff *skb) 6 | { 7 | bpf_printk("new packet captured (XDP)\n"); 8 | return XDP_PASS; 9 | }; 10 | 11 | char _license[] SEC("license") = "GPL"; 12 | __u32 _version SEC("version") = 0xFFFFFFFE; 13 | -------------------------------------------------------------------------------- /examples/programs/xdp/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/sirupsen/logrus" 5 | 6 | "github.com/gojue/ebpfmanager" 7 | ) 8 | 9 | var m = &manager.Manager{ 10 | Probes: []*manager.Probe{ 11 | { 12 | Section: "xdp/ingress", 13 | EbpfFuncName: "egress_cls_func", 14 | Ifindex: 2, // change this to the interface index connected to the internet 15 | XDPAttachMode: manager.XdpAttachModeSkb, 16 | }, 17 | }, 18 | } 19 | 20 | func main() { 21 | // Initialize the manager 22 | if err := m.Init(recoverAssets()); err != nil { 23 | logrus.Fatal(err) 24 | } 25 | 26 | // Start the manager 27 | if err := m.Start(); err != nil { 28 | logrus.Fatal(err) 29 | } 30 | 31 | logrus.Println("successfully started, head over to /sys/kernel/debug/tracing/trace_pipe") 32 | 33 | // Generate some network traffic to trigger the probe 34 | trigger() 35 | 36 | // Close the manager 37 | if err := m.Stop(manager.CleanAll); err != nil { 38 | logrus.Fatal(err) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/programs/xdp/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "github.com/sirupsen/logrus" 8 | "io" 9 | "net/http" 10 | ) 11 | 12 | // recoverAssets - Recover ebpf asset 13 | func recoverAssets() io.ReaderAt { 14 | buf, err := Asset("/probe.o") 15 | if err != nil { 16 | logrus.Fatal(errors.New(fmt.Sprintf("error:%v , couldn't find asset", err))) 17 | } 18 | return bytes.NewReader(buf) 19 | } 20 | 21 | // trigger - Generate some network traffic to trigger the probe 22 | func trigger() { 23 | logrus.Println("Generating some network traffic to trigger the probes ...") 24 | _, _ = http.Get("https://www.baidu.com/") 25 | } 26 | -------------------------------------------------------------------------------- /examples/ringbuf_map/Makefile: -------------------------------------------------------------------------------- 1 | all: build-ebpf build run 2 | 3 | build-ebpf: 4 | mkdir -p ebpf/bin 5 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 6 | -Wno-unused-value \ 7 | -Wno-pointer-sign \ 8 | -Wno-compare-distinct-pointer-types \ 9 | -Wunused \ 10 | -Wall \ 11 | -Werror \ 12 | -I/lib/modules/$$(uname -r)/build/include \ 13 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 14 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 15 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 16 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 17 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 18 | -O2 -emit-llvm \ 19 | ebpf/main.c \ 20 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe.o 21 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg main -prefix "ebpf/bin" -o "probe.go" "ebpf/bin/probe.o" 22 | 23 | 24 | build: 25 | go build -o bin/main . 26 | 27 | run: 28 | sudo bin/main 29 | -------------------------------------------------------------------------------- /examples/ringbuf_map/ebpf/include/bpf_map.h: -------------------------------------------------------------------------------- 1 | #define BUF_SIZE_MAP_NS 256 2 | 3 | typedef struct bpf_map_def { 4 | unsigned int type; 5 | unsigned int key_size; 6 | unsigned int value_size; 7 | unsigned int max_entries; 8 | unsigned int map_flags; 9 | unsigned int inner_map_idx; 10 | unsigned int pinning; 11 | char namespace[BUF_SIZE_MAP_NS]; 12 | } bpf_map_def; 13 | 14 | 15 | // 定义结构体 16 | typedef struct ringbuf_bpf_map_def { 17 | unsigned int type; 18 | unsigned int key_size; 19 | unsigned int value_size; 20 | unsigned int max_entries; 21 | unsigned int map_flags; 22 | } ringbuf_bpf_map_def; 23 | 24 | enum bpf_pin_type { 25 | PIN_NONE = 0, 26 | PIN_OBJECT_NS, 27 | PIN_GLOBAL_NS, 28 | PIN_CUSTOM_NS, 29 | }; -------------------------------------------------------------------------------- /examples/ringbuf_map/ebpf/main.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 | /* Copyright (c) 2020 Andrii Nakryiko */ 3 | #include "include/bpf.h" 4 | #include "include/bpf_map.h" 5 | #include "include/bpf_helpers.h" 6 | 7 | 8 | struct ringbuf_bpf_map_def SEC("maps/ringbuf_map") ringbuf_map = { 9 | .type = BPF_MAP_TYPE_RINGBUF, 10 | .max_entries = 256*1024, 11 | }; 12 | 13 | 14 | struct data_t { 15 | u32 pid; 16 | u32 flag; 17 | }; 18 | 19 | SEC("kprobe/vfs_mkdir") 20 | int kprobe_vfs_mkdir(void *ctx) 21 | { 22 | bpf_printk("mkdir_ringbuf (vfs hook point)%u\n",bpf_get_current_pid_tgid()); 23 | struct data_t data = {}; 24 | data.pid = bpf_get_current_pid_tgid(); 25 | data.flag = 1; 26 | bpf_ringbuf_output(&ringbuf_map,&data, sizeof(data), 0 /* flags */); 27 | return 0; 28 | }; 29 | 30 | char _license[] SEC("license") = "GPL"; 31 | __u32 _version SEC("version") = 0xFFFFFFFE; 32 | -------------------------------------------------------------------------------- /examples/ringbuf_map/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "embed" 5 | manager "github.com/gojue/ebpfmanager" 6 | "github.com/gojue/ebpfmanager/kernel" 7 | "github.com/sirupsen/logrus" 8 | ) 9 | 10 | var m = &manager.Manager{ 11 | Probes: []*manager.Probe{ 12 | &manager.Probe{ 13 | UID: "MyFirstHook", 14 | Section: "kprobe/vfs_mkdir", 15 | AttachToFuncName: "vfs_mkdir", 16 | EbpfFuncName: "kprobe_vfs_mkdir", 17 | }, 18 | }, 19 | RingbufMaps: []*manager.RingbufMap{ 20 | &manager.RingbufMap{ 21 | Map: manager.Map{ 22 | Name: "ringbuf_map", 23 | }, 24 | RingbufMapOptions: manager.RingbufMapOptions{ 25 | DataHandler: myDataHandler, 26 | }, 27 | }, 28 | }, 29 | } 30 | 31 | // myDataHandler - Perf event data handler 32 | func myDataHandler(cpu int, data []byte, ringbufmap *manager.RingbufMap, manager *manager.Manager) { 33 | pid := ByteOrder.Uint32(data[0:4]) 34 | flag := ByteOrder.Uint32(data[4:8]) 35 | logrus.Printf("received: CPU:%d pid:%d,flag:%d", cpu, pid, flag) 36 | } 37 | 38 | func main() { 39 | //Initialize the manager 40 | logrus.Println("initializing manager") 41 | kv, err := kernel.HostVersion() 42 | if err != nil { 43 | // nothing to do. 44 | } 45 | if kv < kernel.VersionCode(5, 8, 0) { 46 | logrus.Println(manager.ErrRingbufNotSupported, "current kernel version is:", kv.String()) 47 | return 48 | } 49 | if err := m.Init(recoverAssets()); err != nil { 50 | logrus.Fatal(err) 51 | } 52 | 53 | logrus.Println("successfully started, head over to /sys/kernel/debug/tracing/trace_pipe") 54 | // Start the manager 55 | if err := m.Start(); err != nil { 56 | logrus.Fatal(err) 57 | } 58 | 59 | // Create a folder to trigger the probes 60 | if err := trigger(); err != nil { 61 | logrus.Error(err) 62 | } 63 | 64 | // Close the manager 65 | if err := m.Stop(manager.CleanAll); err != nil { 66 | logrus.Fatal(err) 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /examples/ringbuf_map/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "fmt" 7 | "io" 8 | "os" 9 | "time" 10 | "unsafe" 11 | 12 | "github.com/sirupsen/logrus" 13 | ) 14 | 15 | // ByteOrder - host byte order 16 | var ByteOrder binary.ByteOrder 17 | 18 | func init() { 19 | ByteOrder = getHostByteOrder() 20 | } 21 | 22 | // getHostByteOrder - Returns the host byte order 23 | func getHostByteOrder() binary.ByteOrder { 24 | var i int32 = 0x01020304 25 | u := unsafe.Pointer(&i) 26 | pb := (*byte)(u) 27 | b := *pb 28 | if b == 0x04 { 29 | return binary.LittleEndian 30 | } 31 | 32 | return binary.BigEndian 33 | } 34 | 35 | // recoverAssets - Recover ebpf asset 36 | func recoverAssets() io.ReaderAt { 37 | buf, err := Asset("/probe.o") 38 | if err != nil { 39 | logrus.Fatal(fmt.Errorf("error:%v, %s", err, "couldn't find asset")) 40 | } 41 | return bytes.NewReader(buf) 42 | } 43 | 44 | // trigger - Creates and then removes a tmp folder to trigger the probes 45 | func trigger() error { 46 | logrus.Println("Generating events to trigger the probes ...") 47 | // Creating a tmp directory to trigger the probes 48 | tmpDir := "/tmp/test_folder" 49 | logrus.Printf("creating %v", tmpDir) 50 | err := os.MkdirAll(tmpDir, 0666) 51 | if err != nil { 52 | return err 53 | } 54 | 55 | // Sleep a bit to give time to the perf event 56 | time.Sleep(500 * time.Millisecond) 57 | 58 | // Removing a tmp directory to trigger the probes 59 | logrus.Printf("removing %v", tmpDir) 60 | err = os.RemoveAll(tmpDir) 61 | if err != nil { 62 | return err 63 | } 64 | 65 | // Sleep a bit to give time to the perf event 66 | time.Sleep(500 * time.Millisecond) 67 | return nil 68 | } 69 | -------------------------------------------------------------------------------- /examples/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | run_make() 4 | { 5 | #如果该目录下存在Makefile 6 | if [ -f "Makefile" ]; then 7 | pwd; 8 | make || exit 1; 9 | fi 10 | } 11 | 12 | testmakes() 13 | { 14 | cd $1; 15 | run_make; 16 | # shellcheck disable=SC2045 17 | for x in $(ls .) 18 | do 19 | if [ -d "$x" ];then 20 | testmakes $x; 21 | cd .. 22 | fi 23 | 24 | done 25 | } 26 | 27 | testmakes . -------------------------------------------------------------------------------- /examples/tests_and_benchmarks/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | ebpf/bin/ 3 | -------------------------------------------------------------------------------- /examples/tests_and_benchmarks/Makefile: -------------------------------------------------------------------------------- 1 | all: build-ebpf build run 2 | 3 | build-ebpf: 4 | mkdir -p ebpf/bin 5 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 6 | -Wno-unused-value \ 7 | -Wno-pointer-sign \ 8 | -Wno-compare-distinct-pointer-types \ 9 | -Wunused \ 10 | -Wall \ 11 | -Werror \ 12 | -I/lib/modules/$$(uname -r)/build/include \ 13 | -I/lib/modules/$$(uname -r)/build/include/uapi \ 14 | -I/lib/modules/$$(uname -r)/build/include/generated/uapi \ 15 | -I/lib/modules/$$(uname -r)/build/arch/x86/include \ 16 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/uapi \ 17 | -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated \ 18 | -O2 -emit-llvm \ 19 | ebpf/main.c \ 20 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe.o 21 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg main -prefix "ebpf/bin" -o "probe.go" "ebpf/bin/probe.o" 22 | 23 | build: 24 | go build -o bin/main . 25 | 26 | run: 27 | sudo bin/main 28 | -------------------------------------------------------------------------------- /examples/tests_and_benchmarks/ebpf/include/bpf_map.h: -------------------------------------------------------------------------------- 1 | #define BUF_SIZE_MAP_NS 256 2 | 3 | typedef struct bpf_map_def { 4 | unsigned int type; 5 | unsigned int key_size; 6 | unsigned int value_size; 7 | unsigned int max_entries; 8 | unsigned int map_flags; 9 | unsigned int inner_map_idx; 10 | unsigned int pinning; 11 | char namespace[BUF_SIZE_MAP_NS]; 12 | } bpf_map_def; 13 | 14 | enum bpf_pin_type { 15 | PIN_NONE = 0, 16 | PIN_OBJECT_NS, 17 | PIN_GLOBAL_NS, 18 | PIN_CUSTOM_NS, 19 | }; 20 | -------------------------------------------------------------------------------- /examples/tests_and_benchmarks/ebpf/main.c: -------------------------------------------------------------------------------- 1 | #include "include/bpf.h" 2 | #include "include/bpf_map.h" 3 | #include "include/bpf_helpers.h" 4 | 5 | __attribute__((always_inline)) static int my_func(u32 input) 6 | { 7 | return 2*input; 8 | } 9 | 10 | #define TEST_DATA_KEY 1 11 | 12 | struct my_func_test_data_t { 13 | u32 input; 14 | u32 output; 15 | }; 16 | 17 | struct bpf_map_def SEC("maps/my_func_test_data") my_func_test_data = { 18 | .type = BPF_MAP_TYPE_ARRAY, 19 | .key_size = sizeof(u32), 20 | .value_size = sizeof(struct my_func_test_data_t), 21 | .max_entries = 2, 22 | }; 23 | 24 | SEC("xdp/my_func_test") 25 | int my_func_test(struct __sk_buff *skb) 26 | { 27 | // Retrieve test data 28 | u32 key = TEST_DATA_KEY; 29 | struct my_func_test_data_t *data = bpf_map_lookup_elem(&my_func_test_data, &key); 30 | if (data == NULL) { 31 | bpf_printk("no test data\n"); 32 | return -1; 33 | } 34 | u32 ret = my_func(data->input); 35 | if (ret != data->output) { 36 | bpf_printk("expected %d for input %d, got %d\n", data->output, data->input, ret); 37 | return -1; 38 | } 39 | return 0; 40 | }; 41 | 42 | char _license[] SEC("license") = "GPL"; 43 | __u32 _version SEC("version") = 0xFFFFFFFE; 44 | -------------------------------------------------------------------------------- /examples/tests_and_benchmarks/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/cilium/ebpf" 6 | "github.com/sirupsen/logrus" 7 | 8 | "github.com/gojue/ebpfmanager" 9 | ) 10 | 11 | type TestData struct { 12 | Input uint32 13 | Output uint32 14 | } 15 | 16 | func (td TestData) String() string { 17 | return fmt.Sprintf("{ Input:%v Output:%v }", td.Input, td.Output) 18 | } 19 | 20 | var testDataKey = uint32(1) 21 | 22 | var testData = []TestData{ 23 | {2, 4}, 24 | {10, 20}, 25 | {42, 128}, 26 | {42, 84}, 27 | } 28 | 29 | func main() { 30 | // Initialize the manager 31 | var m = &manager.Manager{} 32 | if err := m.Init(recoverAssets()); err != nil { 33 | logrus.Fatal(err) 34 | } 35 | 36 | // Get map used to send tests 37 | testMap, found, err := m.GetMap("my_func_test_data") 38 | if !found || err != nil { 39 | logrus.Fatalf("couldn't retrieve my_func_test_data %v", err) 40 | } 41 | 42 | // Get xdp program used to trigger the tests 43 | testProgs, found, err := m.GetProgram( 44 | manager.ProbeIdentificationPair{ 45 | EbpfFuncName: "my_func_test", 46 | }, 47 | ) 48 | if !found || err != nil { 49 | logrus.Fatalf("couldn't retrieve my_func_test %v", err) 50 | } 51 | testProg := testProgs[0] 52 | 53 | // Run test 54 | runtTest(testMap, testProg) 55 | 56 | // Run benchmark 57 | runtBenchmark(testMap, testProg) 58 | } 59 | 60 | func runtTest(testMap *ebpf.Map, testProg *ebpf.Program) { 61 | logrus.Println("Running tests ...") 62 | for _, data := range testData { 63 | // insert data 64 | testMap.Put(testDataKey, data) 65 | 66 | // Trigger test - (the 14 bytes is for the minimum packet size required to test an XDP program) 67 | outLen, _, err := testProg.Test(make([]byte, 14)) 68 | if err != nil { 69 | logrus.Fatal(err) 70 | } 71 | if outLen == 0 { 72 | logrus.Printf("%v - PASS", data) 73 | } else { 74 | logrus.Printf("%v - FAIL (checkout /sys/kernel/debug/tracing/trace_pipe to see the logs)", data) 75 | } 76 | } 77 | } 78 | 79 | func runtBenchmark(testMap *ebpf.Map, testProg *ebpf.Program) { 80 | logrus.Println("Running benchmark ...") 81 | for _, data := range testData { 82 | // insert data 83 | testMap.Put(testDataKey, data) 84 | 85 | // Trigger test 86 | outLen, duration, err := testProg.Benchmark(make([]byte, 14), 1000, nil) 87 | if err != nil { 88 | logrus.Fatal(err) 89 | } 90 | if outLen == 0 { 91 | logrus.Printf("%v - PASS (duration: %v)", data, duration) 92 | } else { 93 | logrus.Printf("%v - benchmark FAILED (checkout /sys/kernel/debug/tracing/trace_pipe to see the logs)", data) 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /examples/tests_and_benchmarks/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "github.com/sirupsen/logrus" 8 | "io" 9 | ) 10 | 11 | // recoverAssets - Recover ebpf asset 12 | func recoverAssets() io.ReaderAt { 13 | buf, err := Asset("/probe.o") 14 | if err != nil { 15 | logrus.Fatal(errors.New(fmt.Sprintf("error:%v , couldn't find asset", err))) 16 | } 17 | return bytes.NewReader(buf) 18 | } 19 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/gojue/ebpfmanager 2 | 3 | go 1.24.3 4 | 5 | require ( 6 | github.com/avast/retry-go v3.0.0+incompatible 7 | github.com/cilium/ebpf v0.18.0 8 | github.com/florianl/go-tc v0.4.5 9 | github.com/hashicorp/go-multierror v1.1.1 10 | github.com/shuLhan/go-bindata v4.0.0+incompatible 11 | github.com/sirupsen/logrus v1.9.3 12 | github.com/vishvananda/netlink v1.3.1 13 | golang.org/x/sys v0.33.0 14 | ) 15 | 16 | require ( 17 | github.com/google/go-cmp v0.7.0 // indirect 18 | github.com/hashicorp/errwrap v1.1.0 // indirect 19 | github.com/josharian/native v1.1.0 // indirect 20 | github.com/mdlayher/netlink v1.7.2 // indirect 21 | github.com/mdlayher/socket v0.5.1 // indirect 22 | github.com/vishvananda/netns v0.0.5 // indirect 23 | golang.org/x/net v0.40.0 // indirect 24 | golang.org/x/sync v0.14.0 // indirect 25 | ) 26 | -------------------------------------------------------------------------------- /kernel/kernel_version.go: -------------------------------------------------------------------------------- 1 | //go:build linux 2 | // +build linux 3 | 4 | // Copyright 2016-2017 Kinvolk 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package kernel 19 | 20 | import ( 21 | "fmt" 22 | "io/ioutil" 23 | "regexp" 24 | "strconv" 25 | "strings" 26 | "syscall" 27 | ) 28 | 29 | var versionRegex = regexp.MustCompile(`^(\d+)\.(\d+)(?:.(\d+))?.*$`) 30 | 31 | // KernelVersionFromReleaseString converts a release string with format 32 | // 4.4.2[-1] to a kernel version number in LINUX_VERSION_CODE format. 33 | // That is, for kernel "a.b.c", the version number will be (a<<16 + b<<8 + c) 34 | func KernelVersionFromReleaseString(releaseString string) (uint32, error) { 35 | versionParts := versionRegex.FindStringSubmatch(releaseString) 36 | if len(versionParts) < 3 { 37 | return 0, fmt.Errorf("got invalid release version %q (expected format '4.3.2-1')", releaseString) 38 | } 39 | var major, minor, patch uint64 40 | var err error 41 | major, err = strconv.ParseUint(versionParts[1], 10, 8) 42 | if err != nil { 43 | return 0, err 44 | } 45 | 46 | minor, err = strconv.ParseUint(versionParts[2], 10, 8) 47 | if err != nil { 48 | return 0, err 49 | } 50 | 51 | // patch is optional 52 | if len(versionParts) >= 4 { 53 | patch, _ = strconv.ParseUint(versionParts[3], 10, 8) 54 | } 55 | 56 | // clamp patch/sublevel to 255 EARLY in 4.14.252 because they merged this too early: 57 | // https://github.com/torvalds/linux/commit/e131e0e880f942f138c4b5e6af944c7ddcd7ec96 58 | if major == 4 && minor == 14 && patch >= 252 { 59 | patch = 255 60 | } 61 | 62 | out := major*256*256 + minor*256 + patch 63 | return uint32(out), nil 64 | } 65 | 66 | func currentVersionUname() (uint32, error) { 67 | var buf syscall.Utsname 68 | if err := syscall.Uname(&buf); err != nil { 69 | return 0, err 70 | } 71 | releaseString := strings.Trim(utsnameStr(buf.Release[:]), "\x00") 72 | return KernelVersionFromReleaseString(releaseString) 73 | } 74 | 75 | func currentVersionUbuntu() (uint32, error) { 76 | procVersion, err := ioutil.ReadFile("/proc/version_signature") 77 | if err != nil { 78 | return 0, err 79 | } 80 | return parseUbuntuVersion(string(procVersion)) 81 | } 82 | 83 | func parseUbuntuVersion(procVersion string) (uint32, error) { 84 | var u1, u2, releaseString string 85 | _, err := fmt.Sscanf(procVersion, "%s %s %s", &u1, &u2, &releaseString) 86 | if err != nil { 87 | return 0, err 88 | } 89 | return KernelVersionFromReleaseString(releaseString) 90 | } 91 | 92 | var debianVersionRegex = regexp.MustCompile(`.* SMP Debian (\d+\.\d+.\d+-\d+)(?:\+[[:alnum:]]*)?.*`) 93 | 94 | func parseDebianVersion(str string) (uint32, error) { 95 | match := debianVersionRegex.FindStringSubmatch(str) 96 | if len(match) != 2 { 97 | return 0, fmt.Errorf("failed to parse kernel version from /proc/version: %s", str) 98 | } 99 | return KernelVersionFromReleaseString(match[1]) 100 | } 101 | 102 | func currentVersionDebian() (uint32, error) { 103 | procVersion, err := ioutil.ReadFile("/proc/version") 104 | if err != nil { 105 | return 0, fmt.Errorf("error reading /proc/version: %s", err) 106 | } 107 | 108 | return parseDebianVersion(string(procVersion)) 109 | } 110 | 111 | // CurrentKernelVersion returns the current kernel version in 112 | // LINUX_VERSION_CODE format (see KernelVersionFromReleaseString()) 113 | func CurrentKernelVersion() (uint32, error) { 114 | // We need extra checks for Debian and Ubuntu as they modify 115 | // the kernel version patch number for compatibility with 116 | // out-of-tree modules. Linux perf tools do the same for Ubuntu 117 | // systems: https://github.com/torvalds/linux/commit/d18acd15c 118 | // 119 | // See also: 120 | // https://kernel-handbook.alioth.debian.org/ch-versions.html 121 | // https://wiki.ubuntu.com/Kernel/FAQ 122 | version, err := currentVersionUbuntu() 123 | if err == nil { 124 | return version, nil 125 | } 126 | version, err = currentVersionDebian() 127 | if err == nil { 128 | return version, nil 129 | } 130 | return currentVersionUname() 131 | } 132 | 133 | func utsnameStr(in []int8) string { 134 | out := make([]byte, len(in)) 135 | for i := 0; i < len(in); i++ { 136 | if in[i] == 0 { 137 | break 138 | } 139 | out = append(out, byte(in[i])) 140 | } 141 | return string(out) 142 | } 143 | -------------------------------------------------------------------------------- /kernel/kernel_version_unsupport.go: -------------------------------------------------------------------------------- 1 | //go:build !linux 2 | // +build !linux 3 | 4 | package kernel 5 | 6 | import ( 7 | "fmt" 8 | 9 | "runtime" 10 | ) 11 | 12 | var ErrNonLinux = fmt.Errorf("unsupported platform %s/%s", runtime.GOOS, runtime.GOARCH) 13 | 14 | func KernelVersionFromReleaseString(releaseString string) (uint32, error) { 15 | return 0, ErrNonLinux 16 | } 17 | 18 | func CurrentKernelVersion() (uint32, error) { 19 | return 0, ErrNonLinux 20 | } 21 | -------------------------------------------------------------------------------- /kernel/version.go: -------------------------------------------------------------------------------- 1 | //go:build linux 2 | // +build linux 3 | 4 | package kernel 5 | 6 | import ( 7 | "fmt" 8 | ) 9 | 10 | // Version is a numerical representation of a kernel version 11 | type Version uint32 12 | 13 | var hostVersion Version 14 | 15 | // String returns a string representing the version in x.x.x format 16 | func (v Version) String() string { 17 | a, b, c := v>>16, v>>8&0xff, v&0xff 18 | return fmt.Sprintf("%d.%d.%d", a, b, c) 19 | } 20 | 21 | // HostVersion returns the running kernel version of the host 22 | func HostVersion() (Version, error) { 23 | if hostVersion != 0 { 24 | return hostVersion, nil 25 | } 26 | kv, err := CurrentKernelVersion() 27 | if err != nil { 28 | return 0, err 29 | } 30 | hostVersion = Version(kv) 31 | return hostVersion, nil 32 | } 33 | 34 | // ParseVersion parses a string in the format of x.x.x to a Version 35 | func ParseVersion(s string) Version { 36 | var a, b, c byte 37 | fmt.Sscanf(s, "%d.%d.%d", &a, &b, &c) 38 | return VersionCode(a, b, c) 39 | } 40 | 41 | // VersionCode returns a Version computed from the individual parts of a x.x.x version 42 | func VersionCode(major, minor, patch byte) Version { 43 | // KERNEL_VERSION(a,b,c) = (a << 16) + (b << 8) + (c) 44 | // Per https://github.com/torvalds/linux/blob/db7c953555388571a96ed8783ff6c5745ba18ab9/Makefile#L1250 45 | return Version((uint32(major) << 16) + (uint32(minor) << 8) + uint32(patch)) 46 | } 47 | -------------------------------------------------------------------------------- /ringbuf.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "github.com/cilium/ebpf/ringbuf" 7 | "github.com/gojue/ebpfmanager/kernel" 8 | ) 9 | 10 | // RingbufMapOptions - Perf map specific options 11 | type RingbufMapOptions struct { 12 | // Watermark - The reader will start processing samples once their sizes in the perf ring buffer 13 | // exceed this value. Must be smaller than PerfRingBufferSize. Defaults to the manager value if not set. 14 | Watermark int 15 | 16 | // PerfErrChan - Perf reader error channel 17 | PerfErrChan chan error 18 | 19 | // DataHandler - Callback function called when a new sample was retrieved from the perf 20 | // ring buffer. 21 | DataHandler func(CPU int, data []byte, perfMap *RingbufMap, manager *Manager) 22 | 23 | // PerfMapStats - Perf map statistics event like nr Read errors, lost samples, 24 | // RawSamples bytes count. Need to be initialized via manager.NewPerfMapStats() 25 | PerfMapStats *PerfMapStats 26 | 27 | // DumpHandler - Callback function called when manager.Dump() is called 28 | // and dump the current state (human readable) 29 | DumpHandler func(perfMap *PerfMap, manager *Manager) string 30 | } 31 | 32 | // RingbufMap - ring buffer reader wrapper 33 | type RingbufMap struct { 34 | manager *Manager 35 | ringBufReader *ringbuf.Reader 36 | 37 | // Map - A PerfMap has the same features as a normal Map 38 | Map 39 | RingbufMapOptions 40 | } 41 | 42 | func (m *RingbufMap) Init(manager *Manager) error { 43 | kv, err := kernel.HostVersion() 44 | if err != nil { 45 | // nothing to do. 46 | } 47 | if kv < kernel.VersionCode(5, 8, 0) { 48 | return ErrRingbufNotSupported 49 | } 50 | m.manager = manager 51 | if m.DataHandler == nil { 52 | return fmt.Errorf("no DataHandler set for %s", m.Name) 53 | } 54 | 55 | if m.Watermark == 0 { 56 | m.Watermark = manager.options.DefaultWatermark 57 | } 58 | 59 | // Initialize the underlying map structure 60 | if err := m.Map.Init(manager); err != nil { 61 | return err 62 | } 63 | 64 | return nil 65 | } 66 | 67 | func (m *RingbufMap) Start() error { 68 | m.stateLock.Lock() 69 | defer m.stateLock.Unlock() 70 | 71 | if m.state == running { 72 | return nil 73 | } 74 | if m.state < initialized { 75 | return ErrMapNotInitialized 76 | } 77 | 78 | var err error 79 | m.ringBufReader, err = ringbuf.NewReader(m.array) 80 | if err != nil { 81 | return err 82 | } 83 | go func() { 84 | m.manager.wg.Add(1) 85 | for { 86 | record, err := m.ringBufReader.Read() 87 | if err != nil { 88 | if errors.Is(err, ringbuf.ErrClosed) { 89 | m.manager.wg.Done() 90 | return 91 | } 92 | } 93 | m.DataHandler(0, record.RawSample, m, m.manager) 94 | } 95 | }() 96 | m.state = running 97 | return nil 98 | } 99 | 100 | func (m *RingbufMap) Stop(cleanup MapCleanupType) error { 101 | m.stateLock.Lock() 102 | defer m.stateLock.Unlock() 103 | 104 | if m.state < running { 105 | return nil 106 | } 107 | err := m.ringBufReader.Close() 108 | m.state = initialized 109 | 110 | // close underlying map 111 | if errTmp := m.Map.close(cleanup); errTmp != nil { 112 | if err == nil { 113 | err = errTmp 114 | } else { 115 | err = fmt.Errorf("error%v, %s", errTmp, err.Error()) 116 | } 117 | } 118 | return err 119 | } 120 | -------------------------------------------------------------------------------- /selectors.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | // OneOf - This selector is used to ensure that at least of a list of probe selectors is valid. In other words, this 9 | // can be used to ensure that at least one of a list of optional probes is activated. 10 | type OneOf struct { 11 | Selectors []ProbesSelector 12 | } 13 | 14 | // GetProbesIdentificationPairList - Returns the list of probes that this selector activates 15 | func (oo *OneOf) GetProbesIdentificationPairList() []ProbeIdentificationPair { 16 | var l []ProbeIdentificationPair 17 | for _, selector := range oo.Selectors { 18 | l = append(l, selector.GetProbesIdentificationPairList()...) 19 | } 20 | return l 21 | } 22 | 23 | // RunValidator - Ensures that the probes that were successfully activated follow the selector goal. 24 | // For example, see OneOf. 25 | func (oo *OneOf) RunValidator(manager *Manager) error { 26 | var errs []string 27 | for _, selector := range oo.Selectors { 28 | if err := selector.RunValidator(manager); err != nil { 29 | errs = append(errs, err.Error()) 30 | } 31 | } 32 | if len(errs) == len(oo.Selectors) { 33 | return fmt.Errorf( 34 | "OneOf requirement failed, none of the following probes are running [%s]", 35 | strings.Join(errs, " | ")) 36 | } 37 | // at least one selector was successful 38 | return nil 39 | } 40 | 41 | func (oo *OneOf) String() string { 42 | var strs []string 43 | for _, id := range oo.GetProbesIdentificationPairList() { 44 | str := fmt.Sprintf("%s", id) 45 | strs = append(strs, str) 46 | } 47 | return strings.Join(strs, ", ") 48 | } 49 | 50 | // EditProbeIdentificationPair - Changes all the selectors looking for the old ProbeIdentificationPair so that they 51 | // now select the new one 52 | func (oo *OneOf) EditProbeIdentificationPair(old ProbeIdentificationPair, new ProbeIdentificationPair) { 53 | for _, selector := range oo.Selectors { 54 | selector.EditProbeIdentificationPair(old, new) 55 | } 56 | } 57 | 58 | // AllOf - This selector is used to ensure that all the proves in the provided list are running. 59 | type AllOf struct { 60 | Selectors []ProbesSelector 61 | } 62 | 63 | // GetProbesIdentificationPairList - Returns the list of probes that this selector activates 64 | func (ao *AllOf) GetProbesIdentificationPairList() []ProbeIdentificationPair { 65 | var l []ProbeIdentificationPair 66 | for _, selector := range ao.Selectors { 67 | l = append(l, selector.GetProbesIdentificationPairList()...) 68 | } 69 | return l 70 | } 71 | 72 | // RunValidator - Ensures that the probes that were successfully activated follow the selector goal. 73 | // For example, see OneOf. 74 | func (ao *AllOf) RunValidator(manager *Manager) error { 75 | var errMsg []string 76 | for _, selector := range ao.Selectors { 77 | if err := selector.RunValidator(manager); err != nil { 78 | errMsg = append(errMsg, err.Error()) 79 | } 80 | } 81 | if len(errMsg) > 0 { 82 | return fmt.Errorf( 83 | "AllOf requirement failed, the following probes are not running [%s]", 84 | strings.Join(errMsg, " | ")) 85 | } 86 | // no error means that all the selectors were successful 87 | return nil 88 | } 89 | 90 | func (ao *AllOf) String() string { 91 | var strs []string 92 | for _, id := range ao.GetProbesIdentificationPairList() { 93 | str := fmt.Sprintf("%s", id) 94 | strs = append(strs, str) 95 | } 96 | return strings.Join(strs, ", ") 97 | } 98 | 99 | // EditProbeIdentificationPair - Changes all the selectors looking for the old ProbeIdentificationPair so that they 100 | // now select the new one 101 | func (ao *AllOf) EditProbeIdentificationPair(old ProbeIdentificationPair, new ProbeIdentificationPair) { 102 | for _, selector := range ao.Selectors { 103 | selector.EditProbeIdentificationPair(old, new) 104 | } 105 | } 106 | 107 | // BestEffort - This selector is used to load probes in best effort mode 108 | type BestEffort struct { 109 | Selectors []ProbesSelector 110 | } 111 | 112 | // GetProbesIdentificationPairList - Returns the list of probes that this selector activates 113 | func (be *BestEffort) GetProbesIdentificationPairList() []ProbeIdentificationPair { 114 | var l []ProbeIdentificationPair 115 | for _, selector := range be.Selectors { 116 | l = append(l, selector.GetProbesIdentificationPairList()...) 117 | } 118 | return l 119 | } 120 | 121 | // RunValidator - Ensures that the probes that were successfully activated follow the selector goal. 122 | // For example, see OneOf. 123 | func (be *BestEffort) RunValidator(manager *Manager) error { 124 | return nil 125 | } 126 | 127 | func (be *BestEffort) String() string { 128 | var strs []string 129 | for _, id := range be.GetProbesIdentificationPairList() { 130 | str := fmt.Sprintf("%s", id) 131 | strs = append(strs, str) 132 | } 133 | return strings.Join(strs, ", ") 134 | } 135 | 136 | // EditProbeIdentificationPair - Changes all the selectors looking for the old ProbeIdentificationPair so that they 137 | // now select the new one 138 | func (be *BestEffort) EditProbeIdentificationPair(old ProbeIdentificationPair, new ProbeIdentificationPair) { 139 | for _, selector := range be.Selectors { 140 | selector.EditProbeIdentificationPair(old, new) 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /syscalls.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "golang.org/x/sys/unix" 5 | "syscall" 6 | ) 7 | 8 | func sockAttach(sockFd int, progFd int) error { 9 | return syscall.SetsockoptInt(sockFd, syscall.SOL_SOCKET, unix.SO_ATTACH_BPF, progFd) 10 | } 11 | 12 | func sockDetach(sockFd int, progFd int) error { 13 | return syscall.SetsockoptInt(sockFd, syscall.SOL_SOCKET, unix.SO_DETACH_BPF, progFd) 14 | } 15 | -------------------------------------------------------------------------------- /testdata/Makefile: -------------------------------------------------------------------------------- 1 | LLVM_PREFIX ?= /usr/bin 2 | CLANG ?= $(LLVM_PREFIX)/clang 3 | 4 | all: rewrite.elf 5 | 6 | clean: 7 | -$(RM) *.elf 8 | 9 | %.elf : %.c 10 | $(CLANG) -target bpf -O2 -g \ 11 | -Wall -Werror \ 12 | -c $< -o $@ 13 | -------------------------------------------------------------------------------- /testdata/common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef unsigned int uint32_t; 4 | typedef unsigned long uint64_t; 5 | 6 | #define __section(NAME) __attribute__((section(NAME), used)) 7 | 8 | #define BPF_MAP_TYPE_ARRAY (1) 9 | #define BPF_MAP_TYPE_PERF_EVENT_ARRAY (4) 10 | #define BPF_MAP_TYPE_ARRAY_OF_MAPS (12) 11 | #define BPF_MAP_TYPE_HASH_OF_MAPS (13) 12 | 13 | #define BPF_F_NO_PREALLOC (1U << 0) 14 | #define BPF_F_CURRENT_CPU (0xffffffffULL) 15 | 16 | struct map { 17 | uint32_t type; 18 | uint32_t key_size; 19 | uint32_t value_size; 20 | uint32_t max_entries; 21 | uint32_t flags; 22 | uint32_t inner_map_idx; 23 | uint32_t dummy; 24 | }; 25 | 26 | static void* (*map_lookup_elem)(const void *map, const void *key) = (void*)1; 27 | static int (*perf_event_output)(const void *ctx, const void *map, uint64_t index, const void *data, uint64_t size) = (void*)25; 28 | static uint32_t (*get_smp_processor_id)(void) = (void*)8; 29 | -------------------------------------------------------------------------------- /testdata/rewrite.c: -------------------------------------------------------------------------------- 1 | /* This file tests rewriting constants from C compiled code. 2 | */ 3 | 4 | #include "common.h" 5 | 6 | char __license[] __section("license") = "MIT"; 7 | 8 | struct map map_val __section("maps") = { 9 | .type = 1, 10 | .key_size = sizeof(unsigned int), 11 | .value_size = sizeof(unsigned int), 12 | .max_entries = 1, 13 | }; 14 | 15 | #define CONSTANT "constant" 16 | 17 | #define LOAD_CONSTANT(param, var) asm("%0 = " param " ll" : "=r"(var)) 18 | 19 | __section("socket") int rewrite() { 20 | unsigned long acc = 0; 21 | LOAD_CONSTANT(CONSTANT, acc); 22 | return acc; 23 | } 24 | 25 | __section("socket/map") int rewrite_map() { 26 | unsigned int key = 0; 27 | unsigned int *value = map_lookup_elem(&map_val, &key); 28 | if (!value) { 29 | return 0; 30 | } 31 | return *value; 32 | } 33 | -------------------------------------------------------------------------------- /testdata/rewrite.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gojue/ebpfmanager/80670ed5a287e243e99c6ce5b44333221656201a/testdata/rewrite.elf -------------------------------------------------------------------------------- /tracefs.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | "path/filepath" 8 | "sync" 9 | "syscall" 10 | 11 | "golang.org/x/sys/unix" 12 | ) 13 | 14 | const ( 15 | traceFSRoot = "/sys/kernel/tracing" 16 | debugFSRoot = "/sys/kernel/debug/tracing" 17 | ) 18 | 19 | var ( 20 | tracingRoot = struct { 21 | once sync.Once 22 | path string 23 | err error 24 | }{} 25 | ) 26 | 27 | func getTracefsRoot() (string, error) { 28 | tracingRoot.once.Do(func() { 29 | var statfs unix.Statfs_t 30 | var traceError error 31 | if traceError = unix.Statfs(traceFSRoot, &statfs); traceError == nil { 32 | if statfs.Type == unix.TRACEFS_MAGIC { 33 | tracingRoot.path = traceFSRoot 34 | return 35 | } 36 | traceError = fmt.Errorf("%s is not mounted with tracefs filesystem type", traceFSRoot) 37 | } 38 | var debugError error 39 | if debugError = unix.Statfs(debugFSRoot, &statfs); debugError == nil { 40 | if statfs.Type == unix.TRACEFS_MAGIC || statfs.Type == unix.DEBUGFS_MAGIC { 41 | tracingRoot.path = debugFSRoot 42 | return 43 | } 44 | debugError = fmt.Errorf("%s is not mounted with tracefs or debugfs filesystem type", debugFSRoot) 45 | } 46 | 47 | bestError := fmt.Errorf("tracefs: %s", traceError) 48 | // only fallback to debugfs error if tracefs doesn't exist at all and debugfs does 49 | if errors.Is(traceError, syscall.ENOENT) && !errors.Is(debugError, syscall.ENOENT) { 50 | bestError = fmt.Errorf("debugfs: %s", debugError) 51 | } 52 | tracingRoot.err = fmt.Errorf("tracefs or debugfs is not available: %s", bestError) 53 | }) 54 | return tracingRoot.path, tracingRoot.err 55 | } 56 | 57 | // Root returns the tracing root path in use, `/sys/kernel/tracing` (tracefs) or `/sys/kernel/debug/tracing` (debugfs) 58 | func TracefsRoot() (string, error) { 59 | return getTracefsRoot() 60 | } 61 | 62 | // ReadFile reads the relative path provided, using the detected root of tracefs or debugfs 63 | func TracefsReadFile(relname string) ([]byte, error) { 64 | root, err := getTracefsRoot() 65 | if err != nil { 66 | return nil, err 67 | } 68 | return os.ReadFile(filepath.Join(root, relname)) 69 | } 70 | 71 | // Open opens the relative path provided (similar to os.Open), using the detected root of tracefs or debugfs 72 | func TracefsOpen(relname string) (*os.File, error) { 73 | return TracefsOpenFile(relname, os.O_RDONLY, 0) 74 | } 75 | 76 | // OpenFile opens the relative path provided (similar to os.OpenFile), using the detected root of tracefs or debugfs 77 | func TracefsOpenFile(relname string, flag int, perm os.FileMode) (*os.File, error) { 78 | root, err := getTracefsRoot() 79 | if err != nil { 80 | return nil, err 81 | } 82 | return os.OpenFile(filepath.Join(root, relname), flag, perm) 83 | } 84 | -------------------------------------------------------------------------------- /utils_test.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func TestGenerateEventName(t *testing.T) { 9 | probeType := "p" 10 | funcName := "func" 11 | UID := "UID" 12 | kprobeAttachPID := 1234 13 | 14 | eventName, err := GenerateEventName(probeType, funcName, UID, kprobeAttachPID) 15 | if err != nil { 16 | t.Error(err) 17 | } 18 | if len(eventName) > maxEventNameLen { 19 | t.Errorf("Event name too long, kernel limit is %d : maxEventNameLen", maxEventNameLen) 20 | } 21 | 22 | // should be truncated 23 | funcName = "01234567890123456790123456789012345678901234567890123456789" 24 | eventName, err = GenerateEventName(probeType, funcName, UID, kprobeAttachPID) 25 | if (err != nil) || (len(eventName) != maxEventNameLen) || (eventName != "p_01234567890123456790123456789012345678901234567890123_UID_1234") { 26 | t.Errorf("Should not failed and truncate the function name (len %d)", len(eventName)) 27 | } 28 | 29 | UID = "12345678901234567890123456789012345678901234567890" 30 | _, err = GenerateEventName(probeType, funcName, UID, kprobeAttachPID) 31 | if err == nil { 32 | t.Errorf("Test should failed as event name length is too big for the kernel and free space for function Name is < %d", minFunctionNameLen) 33 | } 34 | } 35 | 36 | func TestGetSyscallFnNameWithSymFile(t *testing.T) { 37 | expectedFnName := "sys_exit" 38 | 39 | fnName, err := GetSyscallFnNameWithSymFile(expectedFnName, "") 40 | if err != nil { 41 | t.Error(err) 42 | } 43 | if !strings.HasSuffix(fnName, expectedFnName) { 44 | t.Errorf("Expected function name %s, but got %s", expectedFnName, fnName) 45 | } 46 | t.Logf("Expected function name %s, got %s", expectedFnName, fnName) 47 | } 48 | --------------------------------------------------------------------------------