├── .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)
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 |
--------------------------------------------------------------------------------