├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── cmd └── ebpfkit-monitor │ ├── main.go │ └── run │ ├── cmd.go │ └── ebpfkit_monitor.go ├── ebpf ├── .gitignore ├── bpf │ ├── bpf.h │ ├── bpf_helpers.h │ └── bpf_map.h ├── main.c └── monitor │ ├── bpf.h │ ├── context.h │ ├── defs.h │ └── exec.h ├── go.mod ├── go.sum ├── graphs └── output.svg ├── pkg ├── assets │ └── probe.go ├── model │ ├── byteorder.go │ ├── const.go │ ├── event.go │ └── options.go └── monitor │ ├── graph.go │ ├── kernel │ └── kernel.go │ ├── manager.go │ ├── monitor.go │ ├── syscall_helpers.go │ └── utils.go └── tools.go /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea/ 3 | bin/ 4 | vendor/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: build-ebpf build 2 | 3 | build-ebpf: 4 | mkdir -p ebpf/bin 5 | clang -D__KERNEL__ -D__ASM_SYSREG_H \ 6 | -DUSE_SYSCALL_WRAPPER=1 \ 7 | -DKBUILD_MODNAME=\"ebpfkit_monitor\" \ 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/main.c \ 22 | -c -o - | llc -march=bpf -filetype=obj -o ebpf/bin/probe.o 23 | go run github.com/shuLhan/go-bindata/cmd/go-bindata -pkg assets -prefix "ebpf/bin" -o "pkg/assets/probe.go" "ebpf/bin/probe.o" 24 | 25 | build: 26 | mkdir -p bin/ 27 | go build -o bin/ ./cmd/ebpfkit-monitor 28 | 29 | install: 30 | sudo cp ./bin/ebpfkit-monitor /usr/bin/ 31 | 32 | run: 33 | sudo ./bin/ebpfkit-monitor start --allowed-processes "/usr/sbin/bpftool" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ebpfkit-monitor 2 | 3 | [![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-blue.svg)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) 4 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) 5 | 6 | `ebpfkit-monitor` is an utility that you can use to statically analyse eBPF bytecode or monitor suspicious eBPF activity at runtime. It was specifically designed to detect [`ebpfkit`](https://github.com/Gui774ume/ebpfkit). 7 | 8 | ## **Disclaimer** 9 | This project is **not** an official Datadog product (experimental or otherwise), it is just code that happens to be developed by Datadog employees as part of an independent security research project. The rootkit herein is provided for educational purposes only and for those who are willing and curious to learn about ethical hacking, security and penetration testing with eBPF. 10 | 11 | **Do not attempt to use these tools to violate the law. The author is not responsible for any illegal action. Misuse of the provided information can result in criminal charges.** 12 | 13 | ## System requirements 14 | 15 | - golang 1.13+ 16 | - This project was developed on a Ubuntu Focal machine (Linux Kernel 5.4) 17 | - Kernel headers are expected to be installed in `lib/modules/$(uname -r)` (see `Makefile`) 18 | - clang & llvm (11.0.1) 19 | - Graphviz (to generate graphs) 20 | - go-bindata (`go get -u github.com/shuLhan/go-bindata/...`) 21 | 22 | ## Build 23 | 24 | 1) To build `ebpfkit-monitor`, run: 25 | 26 | ```shell script 27 | # ~ make 28 | ``` 29 | 30 | 2) To install `ebpfkit-monitor` (copies `ebpfkit-monitor` to `/usr/bin/ebpfkit-monitor`) run: 31 | ```shell script 32 | # ~ make install 33 | ``` 34 | 35 | ## Getting started 36 | 37 | Run `ebpfkit-monitor -h` to get help. 38 | 39 | ```shell script 40 | # ~ ebpfkit-monitor -h 41 | Usage: 42 | ebpfkit-monitor [command] 43 | 44 | Available Commands: 45 | graph graph generates a graphviz representation of the ELF file 46 | help Help about any command 47 | map prints information about one or multiple maps 48 | prog prints information about one or multiple programs 49 | report prints summarized information about the maps and programs 50 | start start monitoring the bpf syscall at runtime 51 | 52 | Flags: 53 | -h, --help help for ebpfkit-monitor 54 | -l, --log-level string log level (options: panic, fatal, error, warn, info, debug or trace). Set to "debug" to see bpf events. (default "info") 55 | 56 | Use "ebpfkit-monitor [command] --help" for more information about a command. 57 | ``` 58 | 59 | ## Examples 60 | 61 | #### List all the program sections provided in the ELF file 62 | 63 | ```shell 64 | # ~ ebpfkit-monitor prog --asset my_elf_file.o 65 | ``` 66 | 67 | #### Dump the bytecode of a program 68 | 69 | ```shell 70 | # ~ ebpfkit-monitor prog --asset my_elf_file.o --section kprobe/my_program --dump 71 | ``` 72 | 73 | #### List all the programs that use the bpf_probe_write_user eBPF helper 74 | 75 | ```shell 76 | # ~ ebpfkit-monitor prog --asset my_elf_file.o --helper BpfProbeWriteUser 77 | ``` 78 | 79 | #### List all the programs that interact with the "piped_progs" eBPF map 80 | 81 | ```shell 82 | # ~ ebpfkit-monitor prog --asset my_elf_file.o --map piped_progs 83 | ``` 84 | 85 | #### List all the maps declared in the ELF file 86 | 87 | ```shell 88 | # ~ ebpfkit-monitor map --asset my_elf_file.o 89 | ``` 90 | 91 | #### Monitor the bpf syscall and print events to the screen 92 | 93 | ```shell 94 | # ~ sudo ebpfkit-monitor start --log-level debug 95 | ``` 96 | 97 | #### Monitor the bpf syscall and write the captured events in a file 98 | 99 | ```shell 100 | # ~ sudo ebpfkit-monitor start --output /tmp 101 | ``` 102 | 103 | #### Monitor the bpf syscall, write the captured events in a file and ensure that only "bpftool" is allowed to use the "bpf" syscall 104 | 105 | ```shell 106 | # ~ sudo ebpfkit-monitor start --output /tmp --allowed-processes "/usr/sbin/bpftool" 107 | ``` 108 | 109 | #### Generate a graph from the provided ELF file 110 | 111 | ```shell script 112 | # ~ ebpfkit-monitor graph -a my_elf_file.o 113 | INFO[2021-08-03T13:19:12Z] Graph generated: /tmp/ebpfkit-monitor-graph-4104912074 114 | # ~ fdp -Tsvg /tmp/ebpfkit-monitor-graph-4104912074 > ./graphs/output.svg 115 | ``` 116 | 117 | ![output.svg](graphs/output.svg) 118 | 119 | ## Future work 120 | 121 | - Move the project to BTF & CO-RE 122 | - Use `lsm` eBPF programs instead of `bpf_override_return` for access control 123 | 124 | ## License 125 | 126 | - The golang code is under Apache 2.0 License. 127 | - The eBPF programs are under the GPL v2 License. -------------------------------------------------------------------------------- /cmd/ebpfkit-monitor/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 GUILLAUME FOURNIER 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "github.com/sirupsen/logrus" 21 | 22 | "github.com/Gui774ume/ebpfkit-monitor/cmd/ebpfkit-monitor/run" 23 | ) 24 | 25 | func main() { 26 | logrus.SetFormatter(&logrus.TextFormatter{ 27 | FullTimestamp: true, 28 | TimestampFormat: "2006-01-02T15:04:05Z", 29 | DisableLevelTruncation: true, 30 | }) 31 | run.EBPFKitMonitor.Execute() 32 | } 33 | -------------------------------------------------------------------------------- /cmd/ebpfkit-monitor/run/cmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 GUILLAUME FOURNIER 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package run 18 | 19 | import ( 20 | "github.com/Gui774ume/ebpfkit-monitor/pkg/model" 21 | "github.com/spf13/cobra" 22 | ) 23 | 24 | // EBPFKitMonitor represents the base command of ebpfkit-monitor 25 | var EBPFKitMonitor = &cobra.Command{ 26 | Use: "ebpfkit-monitor", 27 | } 28 | 29 | var prog = &cobra.Command{ 30 | Use: "prog", 31 | Short: "prints information about one or multiple programs", 32 | Long: "prints information about one or multiple programs from the provided ELF file", 33 | RunE: progCmd, 34 | } 35 | 36 | var m = &cobra.Command{ 37 | Use: "map", 38 | Short: "prints information about one or multiple maps", 39 | Long: "prints information about one or multiple maps from the provided ELF file", 40 | RunE: mapCmd, 41 | } 42 | 43 | var report = &cobra.Command{ 44 | Use: "report", 45 | Short: "prints summarized information about the maps and programs", 46 | Long: "prints summarized information about the maps and programs in the provided ELF file", 47 | RunE: reportCmd, 48 | } 49 | 50 | var graph = &cobra.Command{ 51 | Use: "graph", 52 | Short: "graph generates a graphviz representation of the ELF file", 53 | Long: "graph generates a graphviz representation of the ELF file", 54 | RunE: graphCmd, 55 | } 56 | 57 | var start = &cobra.Command{ 58 | Use: "start", 59 | Short: "start monitoring the bpf syscall at runtime", 60 | Long: "start monitoring the bpf syscall at runtime and look for malicious behavior", 61 | RunE: startCmd, 62 | } 63 | 64 | var options model.EBPFKitOptions 65 | 66 | func init() { 67 | EBPFKitMonitor.PersistentFlags().VarP( 68 | model.NewLogLevelSanitizer(&options.LogLevel), 69 | "log-level", 70 | "l", 71 | `log level (options: panic, fatal, error, warn, info, debug or trace). Set to "debug" to see bpf events.`) 72 | 73 | prog.Flags().StringVarP( 74 | &options.Section, 75 | "section", 76 | "s", 77 | "", 78 | "program section to dump") 79 | prog.Flags().StringVar( 80 | &options.Helper, 81 | "helper", 82 | "", 83 | "program section eBPF helper selector") 84 | prog.Flags().StringVar( 85 | &options.Map, 86 | "map", 87 | "", 88 | "map section selector") 89 | prog.Flags().BoolVarP( 90 | &options.Dump, 91 | "dump", 92 | "d", 93 | false, 94 | "dump the program bytecode") 95 | prog.Flags().StringVarP( 96 | &options.EBPFAssetPath, 97 | "asset", 98 | "a", 99 | "", 100 | "path to the eBPF asset (ELF format expected)") 101 | _ = prog.MarkFlagRequired("asset") 102 | 103 | m.Flags().StringVarP( 104 | &options.Section, 105 | "section", 106 | "s", 107 | "", 108 | "map section to dump") 109 | m.Flags().StringVarP( 110 | &options.EBPFAssetPath, 111 | "asset", 112 | "a", 113 | "", 114 | "path to the eBPF asset (ELF format expected)") 115 | _ = m.MarkFlagRequired("asset") 116 | 117 | graph.Flags().StringVarP( 118 | &options.EBPFAssetPath, 119 | "asset", 120 | "a", 121 | "", 122 | "path to the eBPF asset (ELF format expected)") 123 | _ = graph.MarkFlagRequired("asset") 124 | 125 | report.Flags().StringVarP( 126 | &options.EBPFAssetPath, 127 | "asset", 128 | "a", 129 | "", 130 | "path to the eBPF asset (ELF format expected)") 131 | _ = report.MarkFlagRequired("asset") 132 | 133 | start.Flags().StringArrayVar( 134 | &options.AllowedProcesses, 135 | "allowed-processes", 136 | []string{}, 137 | "defines the list of binary paths which processes are allowed to use the bpf syscall. Each path will be truncated past its first 350 characters. When this parameter is not set, any process can use the bpf syscall.", 138 | ) 139 | start.Flags().StringVarP( 140 | &options.OutputDirectory, 141 | "output", 142 | "o", 143 | "", 144 | "output directory for the collected events (json)", 145 | ) 146 | 147 | EBPFKitMonitor.AddCommand(prog) 148 | EBPFKitMonitor.AddCommand(m) 149 | EBPFKitMonitor.AddCommand(report) 150 | EBPFKitMonitor.AddCommand(graph) 151 | EBPFKitMonitor.AddCommand(start) 152 | } 153 | -------------------------------------------------------------------------------- /cmd/ebpfkit-monitor/run/ebpfkit_monitor.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 GUILLAUME FOURNIER 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package run 18 | 19 | import ( 20 | "fmt" 21 | "os" 22 | "os/signal" 23 | 24 | "github.com/sirupsen/logrus" 25 | "github.com/spf13/cobra" 26 | 27 | "github.com/Gui774ume/ebpfkit-monitor/pkg/monitor" 28 | ) 29 | 30 | func progCmd(cmd *cobra.Command, args []string) error { 31 | mon, err := monitor.NewMonitor(options) 32 | if err != nil { 33 | logrus.Fatalf("failed to run ebpfkit-monitor: %v", err) 34 | } 35 | if err = mon.ShowProgram(options.Section, options.Dump, options.Helper, options.Map); err != nil { 36 | logrus.Fatalf("failed to run ebpfkit-monitor: %v", err) 37 | } 38 | return nil 39 | } 40 | 41 | func mapCmd(cmd *cobra.Command, args []string) error { 42 | mon, err := monitor.NewMonitor(options) 43 | if err != nil { 44 | logrus.Fatalf("failed to run ebpfkit-monitor: %v", err) 45 | } 46 | if err = mon.ShowMap(options.Section); err != nil { 47 | logrus.Fatalf("failed to run ebpfkit-monitor: %v", err) 48 | } 49 | return nil 50 | } 51 | 52 | func reportCmd(cmd *cobra.Command, args []string) error { 53 | mon, err := monitor.NewMonitor(options) 54 | if err != nil { 55 | logrus.Fatalf("failed to run ebpfkit-monitor: %v", err) 56 | } 57 | if err = mon.ShowReport(); err != nil { 58 | logrus.Fatalf("failed to run ebpfkit-monitor: %v", err) 59 | } 60 | return nil 61 | } 62 | 63 | func graphCmd(cmd *cobra.Command, args []string) error { 64 | mon, err := monitor.NewMonitor(options) 65 | if err != nil { 66 | logrus.Fatalf("failed to run ebpfkit-monitor: %v", err) 67 | } 68 | if err = mon.GenerateGraph(options.EBPFAssetPath); err != nil { 69 | logrus.Fatalf("failed to run ebpfkit-monitor: %v", err) 70 | } 71 | return nil 72 | } 73 | 74 | func startCmd(cmd *cobra.Command, args []string) error { 75 | mon, err := monitor.NewMonitor(options) 76 | if err != nil { 77 | logrus.Fatalf("failed to run ebpfkit-monitor: %v", err) 78 | } 79 | if err = mon.Start(); err != nil { 80 | logrus.Fatalf("failed to start ebpfkit-monitor: %v", err) 81 | } 82 | 83 | wait() 84 | 85 | if err = mon.Stop(); err != nil { 86 | logrus.Fatalf("failed to stop ebpfkit-monitor: %v", err) 87 | } 88 | return nil 89 | } 90 | 91 | // wait - Waits until an interrupt or kill signal is sent 92 | func wait() { 93 | sig := make(chan os.Signal, 1) 94 | signal.Notify(sig, os.Interrupt, os.Kill) 95 | <-sig 96 | fmt.Println() 97 | } 98 | -------------------------------------------------------------------------------- /ebpf/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | -------------------------------------------------------------------------------- /ebpf/bpf/bpf_helpers.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ 2 | #ifndef __BPF_HELPERS__ 3 | #define __BPF_HELPERS__ 4 | 5 | #define __uint(name, val) int (*name)[val] 6 | #define __type(name, val) val *name 7 | 8 | /* helper macro to print out debug messages */ 9 | #define bpf_printk(fmt, ...) \ 10 | ({ \ 11 | char ____fmt[] = fmt; \ 12 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 13 | ##__VA_ARGS__); \ 14 | }) 15 | 16 | #ifdef __clang__ 17 | 18 | /* helper macro to place programs, maps, license in 19 | * different sections in elf_bpf file. Section names 20 | * are interpreted by elf_bpf loader 21 | */ 22 | #define SEC(NAME) __attribute__((section(NAME), used)) 23 | 24 | /* helper functions called from eBPF programs written in C */ 25 | static void *(*bpf_map_lookup_elem)(void *map, const void *key) = 26 | (void *) BPF_FUNC_map_lookup_elem; 27 | static int (*bpf_map_update_elem)(void *map, const void *key, const void *value, 28 | unsigned long long flags) = 29 | (void *) BPF_FUNC_map_update_elem; 30 | static int (*bpf_map_delete_elem)(void *map, const void *key) = 31 | (void *) BPF_FUNC_map_delete_elem; 32 | static int (*bpf_map_push_elem)(void *map, const void *value, 33 | unsigned long long flags) = 34 | (void *) BPF_FUNC_map_push_elem; 35 | static int (*bpf_map_pop_elem)(void *map, void *value) = 36 | (void *) BPF_FUNC_map_pop_elem; 37 | static int (*bpf_map_peek_elem)(void *map, void *value) = 38 | (void *) BPF_FUNC_map_peek_elem; 39 | static int (*bpf_probe_read)(void *dst, int size, const void *unsafe_ptr) = 40 | (void *) BPF_FUNC_probe_read; 41 | static unsigned long long (*bpf_ktime_get_ns)(void) = 42 | (void *) BPF_FUNC_ktime_get_ns; 43 | static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = 44 | (void *) BPF_FUNC_trace_printk; 45 | static void (*bpf_tail_call)(void *ctx, void *map, int index) = 46 | (void *) BPF_FUNC_tail_call; 47 | static unsigned long long (*bpf_get_smp_processor_id)(void) = 48 | (void *) BPF_FUNC_get_smp_processor_id; 49 | static unsigned long long (*bpf_get_current_pid_tgid)(void) = 50 | (void *) BPF_FUNC_get_current_pid_tgid; 51 | static unsigned long long (*bpf_get_current_uid_gid)(void) = 52 | (void *) BPF_FUNC_get_current_uid_gid; 53 | static int (*bpf_get_current_comm)(void *buf, int buf_size) = 54 | (void *) BPF_FUNC_get_current_comm; 55 | static unsigned long long (*bpf_perf_event_read)(void *map, 56 | unsigned long long flags) = 57 | (void *) BPF_FUNC_perf_event_read; 58 | static int (*bpf_clone_redirect)(void *ctx, int ifindex, int flags) = 59 | (void *) BPF_FUNC_clone_redirect; 60 | static int (*bpf_redirect)(int ifindex, int flags) = 61 | (void *) BPF_FUNC_redirect; 62 | static int (*bpf_redirect_map)(void *map, int key, int flags) = 63 | (void *) BPF_FUNC_redirect_map; 64 | static int (*bpf_perf_event_output)(void *ctx, void *map, 65 | unsigned long long flags, void *data, 66 | int size) = 67 | (void *) BPF_FUNC_perf_event_output; 68 | static int (*bpf_get_stackid)(void *ctx, void *map, int flags) = 69 | (void *) BPF_FUNC_get_stackid; 70 | static int (*bpf_probe_write_user)(void *dst, const void *src, int size) = 71 | (void *) BPF_FUNC_probe_write_user; 72 | static int (*bpf_current_task_under_cgroup)(void *map, int index) = 73 | (void *) BPF_FUNC_current_task_under_cgroup; 74 | static int (*bpf_skb_get_tunnel_key)(void *ctx, void *key, int size, int flags) = 75 | (void *) BPF_FUNC_skb_get_tunnel_key; 76 | static int (*bpf_skb_set_tunnel_key)(void *ctx, void *key, int size, int flags) = 77 | (void *) BPF_FUNC_skb_set_tunnel_key; 78 | static int (*bpf_skb_get_tunnel_opt)(void *ctx, void *md, int size) = 79 | (void *) BPF_FUNC_skb_get_tunnel_opt; 80 | static int (*bpf_skb_set_tunnel_opt)(void *ctx, void *md, int size) = 81 | (void *) BPF_FUNC_skb_set_tunnel_opt; 82 | static unsigned long long (*bpf_get_prandom_u32)(void) = 83 | (void *) BPF_FUNC_get_prandom_u32; 84 | static int (*bpf_xdp_adjust_head)(void *ctx, int offset) = 85 | (void *) BPF_FUNC_xdp_adjust_head; 86 | static int (*bpf_xdp_adjust_meta)(void *ctx, int offset) = 87 | (void *) BPF_FUNC_xdp_adjust_meta; 88 | static int (*bpf_get_socket_cookie)(void *ctx) = 89 | (void *) BPF_FUNC_get_socket_cookie; 90 | static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval, 91 | int optlen) = 92 | (void *) BPF_FUNC_setsockopt; 93 | static int (*bpf_getsockopt)(void *ctx, int level, int optname, void *optval, 94 | int optlen) = 95 | (void *) BPF_FUNC_getsockopt; 96 | static int (*bpf_sock_ops_cb_flags_set)(void *ctx, int flags) = 97 | (void *) BPF_FUNC_sock_ops_cb_flags_set; 98 | static int (*bpf_sk_redirect_map)(void *ctx, void *map, int key, int flags) = 99 | (void *) BPF_FUNC_sk_redirect_map; 100 | static int (*bpf_sk_redirect_hash)(void *ctx, void *map, void *key, int flags) = 101 | (void *) BPF_FUNC_sk_redirect_hash; 102 | static int (*bpf_sock_map_update)(void *map, void *key, void *value, 103 | unsigned long long flags) = 104 | (void *) BPF_FUNC_sock_map_update; 105 | static int (*bpf_sock_hash_update)(void *map, void *key, void *value, 106 | unsigned long long flags) = 107 | (void *) BPF_FUNC_sock_hash_update; 108 | static int (*bpf_perf_event_read_value)(void *map, unsigned long long flags, 109 | void *buf, unsigned int buf_size) = 110 | (void *) BPF_FUNC_perf_event_read_value; 111 | static int (*bpf_perf_prog_read_value)(void *ctx, void *buf, 112 | unsigned int buf_size) = 113 | (void *) BPF_FUNC_perf_prog_read_value; 114 | static int (*bpf_override_return)(void *ctx, unsigned long rc) = 115 | (void *) BPF_FUNC_override_return; 116 | static int (*bpf_msg_redirect_map)(void *ctx, void *map, int key, int flags) = 117 | (void *) BPF_FUNC_msg_redirect_map; 118 | static int (*bpf_msg_redirect_hash)(void *ctx, 119 | void *map, void *key, int flags) = 120 | (void *) BPF_FUNC_msg_redirect_hash; 121 | static int (*bpf_msg_apply_bytes)(void *ctx, int len) = 122 | (void *) BPF_FUNC_msg_apply_bytes; 123 | static int (*bpf_msg_cork_bytes)(void *ctx, int len) = 124 | (void *) BPF_FUNC_msg_cork_bytes; 125 | static int (*bpf_msg_pull_data)(void *ctx, int start, int end, int flags) = 126 | (void *) BPF_FUNC_msg_pull_data; 127 | static int (*bpf_msg_push_data)(void *ctx, int start, int end, int flags) = 128 | (void *) BPF_FUNC_msg_push_data; 129 | static int (*bpf_msg_pop_data)(void *ctx, int start, int cut, int flags) = 130 | (void *) BPF_FUNC_msg_pop_data; 131 | static int (*bpf_bind)(void *ctx, void *addr, int addr_len) = 132 | (void *) BPF_FUNC_bind; 133 | static int (*bpf_xdp_adjust_tail)(void *ctx, int offset) = 134 | (void *) BPF_FUNC_xdp_adjust_tail; 135 | static int (*bpf_skb_get_xfrm_state)(void *ctx, int index, void *state, 136 | int size, int flags) = 137 | (void *) BPF_FUNC_skb_get_xfrm_state; 138 | static int (*bpf_sk_select_reuseport)(void *ctx, void *map, void *key, __u32 flags) = 139 | (void *) BPF_FUNC_sk_select_reuseport; 140 | static int (*bpf_get_stack)(void *ctx, void *buf, int size, int flags) = 141 | (void *) BPF_FUNC_get_stack; 142 | static int (*bpf_fib_lookup)(void *ctx, struct bpf_fib_lookup *params, 143 | int plen, __u32 flags) = 144 | (void *) BPF_FUNC_fib_lookup; 145 | static int (*bpf_lwt_push_encap)(void *ctx, unsigned int type, void *hdr, 146 | unsigned int len) = 147 | (void *) BPF_FUNC_lwt_push_encap; 148 | static int (*bpf_lwt_seg6_store_bytes)(void *ctx, unsigned int offset, 149 | void *from, unsigned int len) = 150 | (void *) BPF_FUNC_lwt_seg6_store_bytes; 151 | static int (*bpf_lwt_seg6_action)(void *ctx, unsigned int action, void *param, 152 | unsigned int param_len) = 153 | (void *) BPF_FUNC_lwt_seg6_action; 154 | static int (*bpf_lwt_seg6_adjust_srh)(void *ctx, unsigned int offset, 155 | unsigned int len) = 156 | (void *) BPF_FUNC_lwt_seg6_adjust_srh; 157 | static int (*bpf_rc_repeat)(void *ctx) = 158 | (void *) BPF_FUNC_rc_repeat; 159 | static int (*bpf_rc_keydown)(void *ctx, unsigned int protocol, 160 | unsigned long long scancode, unsigned int toggle) = 161 | (void *) BPF_FUNC_rc_keydown; 162 | static unsigned long long (*bpf_get_current_cgroup_id)(void) = 163 | (void *) BPF_FUNC_get_current_cgroup_id; 164 | static void *(*bpf_get_local_storage)(void *map, unsigned long long flags) = 165 | (void *) BPF_FUNC_get_local_storage; 166 | static unsigned long long (*bpf_skb_cgroup_id)(void *ctx) = 167 | (void *) BPF_FUNC_skb_cgroup_id; 168 | static unsigned long long (*bpf_skb_ancestor_cgroup_id)(void *ctx, int level) = 169 | (void *) BPF_FUNC_skb_ancestor_cgroup_id; 170 | static struct bpf_sock *(*bpf_sk_lookup_tcp)(void *ctx, 171 | struct bpf_sock_tuple *tuple, 172 | int size, unsigned long long netns_id, 173 | unsigned long long flags) = 174 | (void *) BPF_FUNC_sk_lookup_tcp; 175 | static struct bpf_sock *(*bpf_skc_lookup_tcp)(void *ctx, 176 | struct bpf_sock_tuple *tuple, 177 | int size, unsigned long long netns_id, 178 | unsigned long long flags) = 179 | (void *) BPF_FUNC_skc_lookup_tcp; 180 | static struct bpf_sock *(*bpf_sk_lookup_udp)(void *ctx, 181 | struct bpf_sock_tuple *tuple, 182 | int size, unsigned long long netns_id, 183 | unsigned long long flags) = 184 | (void *) BPF_FUNC_sk_lookup_udp; 185 | static int (*bpf_sk_release)(struct bpf_sock *sk) = 186 | (void *) BPF_FUNC_sk_release; 187 | static int (*bpf_skb_vlan_push)(void *ctx, __be16 vlan_proto, __u16 vlan_tci) = 188 | (void *) BPF_FUNC_skb_vlan_push; 189 | static int (*bpf_skb_vlan_pop)(void *ctx) = 190 | (void *) BPF_FUNC_skb_vlan_pop; 191 | static int (*bpf_rc_pointer_rel)(void *ctx, int rel_x, int rel_y) = 192 | (void *) BPF_FUNC_rc_pointer_rel; 193 | static void (*bpf_spin_lock)(struct bpf_spin_lock *lock) = 194 | (void *) BPF_FUNC_spin_lock; 195 | static void (*bpf_spin_unlock)(struct bpf_spin_lock *lock) = 196 | (void *) BPF_FUNC_spin_unlock; 197 | static struct bpf_sock *(*bpf_sk_fullsock)(struct bpf_sock *sk) = 198 | (void *) BPF_FUNC_sk_fullsock; 199 | static struct bpf_tcp_sock *(*bpf_tcp_sock)(struct bpf_sock *sk) = 200 | (void *) BPF_FUNC_tcp_sock; 201 | static struct bpf_sock *(*bpf_get_listener_sock)(struct bpf_sock *sk) = 202 | (void *) BPF_FUNC_get_listener_sock; 203 | static int (*bpf_skb_ecn_set_ce)(void *ctx) = 204 | (void *) BPF_FUNC_skb_ecn_set_ce; 205 | static int (*bpf_tcp_check_syncookie)(struct bpf_sock *sk, 206 | void *ip, int ip_len, void *tcp, int tcp_len) = 207 | (void *) BPF_FUNC_tcp_check_syncookie; 208 | static int (*bpf_sysctl_get_name)(void *ctx, char *buf, 209 | unsigned long long buf_len, 210 | unsigned long long flags) = 211 | (void *) BPF_FUNC_sysctl_get_name; 212 | static int (*bpf_sysctl_get_current_value)(void *ctx, char *buf, 213 | unsigned long long buf_len) = 214 | (void *) BPF_FUNC_sysctl_get_current_value; 215 | static int (*bpf_sysctl_get_new_value)(void *ctx, char *buf, 216 | unsigned long long buf_len) = 217 | (void *) BPF_FUNC_sysctl_get_new_value; 218 | static int (*bpf_sysctl_set_new_value)(void *ctx, const char *buf, 219 | unsigned long long buf_len) = 220 | (void *) BPF_FUNC_sysctl_set_new_value; 221 | static int (*bpf_strtol)(const char *buf, unsigned long long buf_len, 222 | unsigned long long flags, long *res) = 223 | (void *) BPF_FUNC_strtol; 224 | static int (*bpf_strtoul)(const char *buf, unsigned long long buf_len, 225 | unsigned long long flags, unsigned long *res) = 226 | (void *) BPF_FUNC_strtoul; 227 | static void *(*bpf_sk_storage_get)(void *map, struct bpf_sock *sk, 228 | void *value, __u64 flags) = 229 | (void *) BPF_FUNC_sk_storage_get; 230 | static int (*bpf_sk_storage_delete)(void *map, struct bpf_sock *sk) = 231 | (void *)BPF_FUNC_sk_storage_delete; 232 | static int (*bpf_send_signal)(unsigned sig) = (void *)BPF_FUNC_send_signal; 233 | static long long (*bpf_tcp_gen_syncookie)(struct bpf_sock *sk, void *ip, 234 | int ip_len, void *tcp, int tcp_len) = 235 | (void *) BPF_FUNC_tcp_gen_syncookie; 236 | 237 | /* llvm builtin functions that eBPF C program may use to 238 | * emit BPF_LD_ABS and BPF_LD_IND instructions 239 | */ 240 | struct sk_buff; 241 | unsigned long long load_byte(void *skb, 242 | unsigned long long off) asm("llvm.bpf.load.byte"); 243 | unsigned long long load_half(void *skb, 244 | unsigned long long off) asm("llvm.bpf.load.half"); 245 | unsigned long long load_word(void *skb, 246 | unsigned long long off) asm("llvm.bpf.load.word"); 247 | 248 | #else 249 | 250 | #include 251 | 252 | #endif 253 | 254 | #define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val) \ 255 | struct ____btf_map_##name { \ 256 | type_key key; \ 257 | type_val value; \ 258 | }; \ 259 | struct ____btf_map_##name \ 260 | __attribute__ ((section(".maps." #name), used)) \ 261 | ____btf_map_##name = { } 262 | 263 | static int (*bpf_skb_load_bytes)(void *ctx, int off, void *to, int len) = 264 | (void *) BPF_FUNC_skb_load_bytes; 265 | static int (*bpf_skb_load_bytes_relative)(void *ctx, int off, void *to, int len, __u32 start_header) = 266 | (void *) BPF_FUNC_skb_load_bytes_relative; 267 | static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = 268 | (void *) BPF_FUNC_skb_store_bytes; 269 | static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) = 270 | (void *) BPF_FUNC_l3_csum_replace; 271 | static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) = 272 | (void *) BPF_FUNC_l4_csum_replace; 273 | static int (*bpf_csum_diff)(void *from, int from_size, void *to, int to_size, int seed) = 274 | (void *) BPF_FUNC_csum_diff; 275 | static int (*bpf_skb_under_cgroup)(void *ctx, void *map, int index) = 276 | (void *) BPF_FUNC_skb_under_cgroup; 277 | static int (*bpf_skb_change_head)(void *, int len, int flags) = 278 | (void *) BPF_FUNC_skb_change_head; 279 | static int (*bpf_skb_pull_data)(void *, int len) = 280 | (void *) BPF_FUNC_skb_pull_data; 281 | static unsigned int (*bpf_get_cgroup_classid)(void *ctx) = 282 | (void *) BPF_FUNC_get_cgroup_classid; 283 | static unsigned int (*bpf_get_route_realm)(void *ctx) = 284 | (void *) BPF_FUNC_get_route_realm; 285 | static int (*bpf_skb_change_proto)(void *ctx, __be16 proto, __u64 flags) = 286 | (void *) BPF_FUNC_skb_change_proto; 287 | static int (*bpf_skb_change_type)(void *ctx, __u32 type) = 288 | (void *) BPF_FUNC_skb_change_type; 289 | static unsigned int (*bpf_get_hash_recalc)(void *ctx) = 290 | (void *) BPF_FUNC_get_hash_recalc; 291 | static unsigned long long (*bpf_get_current_task)(void) = 292 | (void *) BPF_FUNC_get_current_task; 293 | static int (*bpf_skb_change_tail)(void *ctx, __u32 len, __u64 flags) = 294 | (void *) BPF_FUNC_skb_change_tail; 295 | static long long (*bpf_csum_update)(void *ctx, __u32 csum) = 296 | (void *) BPF_FUNC_csum_update; 297 | static void (*bpf_set_hash_invalid)(void *ctx) = 298 | (void *) BPF_FUNC_set_hash_invalid; 299 | static int (*bpf_get_numa_node_id)(void) = 300 | (void *) BPF_FUNC_get_numa_node_id; 301 | static int (*bpf_probe_read_str)(void *ctx, __u32 size, 302 | const void *unsafe_ptr) = 303 | (void *) BPF_FUNC_probe_read_str; 304 | static unsigned int (*bpf_get_socket_uid)(void *ctx) = 305 | (void *) BPF_FUNC_get_socket_uid; 306 | static unsigned int (*bpf_set_hash)(void *ctx, __u32 hash) = 307 | (void *) BPF_FUNC_set_hash; 308 | static int (*bpf_skb_adjust_room)(void *ctx, __s32 len_diff, __u32 mode, 309 | unsigned long long flags) = 310 | (void *) BPF_FUNC_skb_adjust_room; 311 | 312 | /* Scan the ARCH passed in from ARCH env variable (see Makefile) */ 313 | #if defined(__TARGET_ARCH_x86) 314 | #define bpf_target_x86 315 | #define bpf_target_defined 316 | #elif defined(__TARGET_ARCH_s390) 317 | #define bpf_target_s390 318 | #define bpf_target_defined 319 | #elif defined(__TARGET_ARCH_arm) 320 | #define bpf_target_arm 321 | #define bpf_target_defined 322 | #elif defined(__TARGET_ARCH_arm64) 323 | #define bpf_target_arm64 324 | #define bpf_target_defined 325 | #elif defined(__TARGET_ARCH_mips) 326 | #define bpf_target_mips 327 | #define bpf_target_defined 328 | #elif defined(__TARGET_ARCH_powerpc) 329 | #define bpf_target_powerpc 330 | #define bpf_target_defined 331 | #elif defined(__TARGET_ARCH_sparc) 332 | #define bpf_target_sparc 333 | #define bpf_target_defined 334 | #else 335 | #undef bpf_target_defined 336 | #endif 337 | 338 | /* Fall back to what the compiler says */ 339 | #ifndef bpf_target_defined 340 | #if defined(__x86_64__) 341 | #define bpf_target_x86 342 | #elif defined(__s390__) 343 | #define bpf_target_s390 344 | #elif defined(__arm__) 345 | #define bpf_target_arm 346 | #elif defined(__aarch64__) 347 | #define bpf_target_arm64 348 | #elif defined(__mips__) 349 | #define bpf_target_mips 350 | #elif defined(__powerpc__) 351 | #define bpf_target_powerpc 352 | #elif defined(__sparc__) 353 | #define bpf_target_sparc 354 | #endif 355 | #endif 356 | 357 | #if defined(bpf_target_x86) 358 | 359 | #ifdef __KERNEL__ 360 | #define PT_REGS_PARM1(x) ((x)->di) 361 | #define PT_REGS_PARM2(x) ((x)->si) 362 | #define PT_REGS_PARM3(x) ((x)->dx) 363 | #define PT_REGS_PARM4(x) ((x)->cx) 364 | #define PT_REGS_PARM5(x) ((x)->r8) 365 | #define PT_REGS_RET(x) ((x)->sp) 366 | #define PT_REGS_FP(x) ((x)->bp) 367 | #define PT_REGS_RC(x) ((x)->ax) 368 | #define PT_REGS_SP(x) ((x)->sp) 369 | #define PT_REGS_IP(x) ((x)->ip) 370 | #else 371 | #ifdef __i386__ 372 | /* i386 kernel is built with -mregparm=3 */ 373 | #define PT_REGS_PARM1(x) ((x)->eax) 374 | #define PT_REGS_PARM2(x) ((x)->edx) 375 | #define PT_REGS_PARM3(x) ((x)->ecx) 376 | #define PT_REGS_PARM4(x) 0 377 | #define PT_REGS_PARM5(x) 0 378 | #define PT_REGS_RET(x) ((x)->esp) 379 | #define PT_REGS_FP(x) ((x)->ebp) 380 | #define PT_REGS_RC(x) ((x)->eax) 381 | #define PT_REGS_SP(x) ((x)->esp) 382 | #define PT_REGS_IP(x) ((x)->eip) 383 | #else 384 | #define PT_REGS_PARM1(x) ((x)->rdi) 385 | #define PT_REGS_PARM2(x) ((x)->rsi) 386 | #define PT_REGS_PARM3(x) ((x)->rdx) 387 | #define PT_REGS_PARM4(x) ((x)->rcx) 388 | #define PT_REGS_PARM5(x) ((x)->r8) 389 | #define PT_REGS_RET(x) ((x)->rsp) 390 | #define PT_REGS_FP(x) ((x)->rbp) 391 | #define PT_REGS_RC(x) ((x)->rax) 392 | #define PT_REGS_SP(x) ((x)->rsp) 393 | #define PT_REGS_IP(x) ((x)->rip) 394 | #endif 395 | #endif 396 | 397 | #elif defined(bpf_target_s390) 398 | 399 | /* s390 provides user_pt_regs instead of struct pt_regs to userspace */ 400 | struct pt_regs; 401 | #define PT_REGS_S390 const volatile user_pt_regs 402 | #define PT_REGS_PARM1(x) (((PT_REGS_S390 *)(x))->gprs[2]) 403 | #define PT_REGS_PARM2(x) (((PT_REGS_S390 *)(x))->gprs[3]) 404 | #define PT_REGS_PARM3(x) (((PT_REGS_S390 *)(x))->gprs[4]) 405 | #define PT_REGS_PARM4(x) (((PT_REGS_S390 *)(x))->gprs[5]) 406 | #define PT_REGS_PARM5(x) (((PT_REGS_S390 *)(x))->gprs[6]) 407 | #define PT_REGS_RET(x) (((PT_REGS_S390 *)(x))->gprs[14]) 408 | /* Works only with CONFIG_FRAME_POINTER */ 409 | #define PT_REGS_FP(x) (((PT_REGS_S390 *)(x))->gprs[11]) 410 | #define PT_REGS_RC(x) (((PT_REGS_S390 *)(x))->gprs[2]) 411 | #define PT_REGS_SP(x) (((PT_REGS_S390 *)(x))->gprs[15]) 412 | #define PT_REGS_IP(x) (((PT_REGS_S390 *)(x))->psw.addr) 413 | 414 | #elif defined(bpf_target_arm) 415 | 416 | #define PT_REGS_PARM1(x) ((x)->uregs[0]) 417 | #define PT_REGS_PARM2(x) ((x)->uregs[1]) 418 | #define PT_REGS_PARM3(x) ((x)->uregs[2]) 419 | #define PT_REGS_PARM4(x) ((x)->uregs[3]) 420 | #define PT_REGS_PARM5(x) ((x)->uregs[4]) 421 | #define PT_REGS_RET(x) ((x)->uregs[14]) 422 | #define PT_REGS_FP(x) ((x)->uregs[11]) /* Works only with CONFIG_FRAME_POINTER */ 423 | #define PT_REGS_RC(x) ((x)->uregs[0]) 424 | #define PT_REGS_SP(x) ((x)->uregs[13]) 425 | #define PT_REGS_IP(x) ((x)->uregs[12]) 426 | 427 | #elif defined(bpf_target_arm64) 428 | 429 | /* arm64 provides struct user_pt_regs instead of struct pt_regs to userspace */ 430 | struct pt_regs; 431 | #define PT_REGS_ARM64 const volatile struct user_pt_regs 432 | #define PT_REGS_PARM1(x) (((PT_REGS_ARM64 *)(x))->regs[0]) 433 | #define PT_REGS_PARM2(x) (((PT_REGS_ARM64 *)(x))->regs[1]) 434 | #define PT_REGS_PARM3(x) (((PT_REGS_ARM64 *)(x))->regs[2]) 435 | #define PT_REGS_PARM4(x) (((PT_REGS_ARM64 *)(x))->regs[3]) 436 | #define PT_REGS_PARM5(x) (((PT_REGS_ARM64 *)(x))->regs[4]) 437 | #define PT_REGS_RET(x) (((PT_REGS_ARM64 *)(x))->regs[30]) 438 | /* Works only with CONFIG_FRAME_POINTER */ 439 | #define PT_REGS_FP(x) (((PT_REGS_ARM64 *)(x))->regs[29]) 440 | #define PT_REGS_RC(x) (((PT_REGS_ARM64 *)(x))->regs[0]) 441 | #define PT_REGS_SP(x) (((PT_REGS_ARM64 *)(x))->sp) 442 | #define PT_REGS_IP(x) (((PT_REGS_ARM64 *)(x))->pc) 443 | 444 | #elif defined(bpf_target_mips) 445 | 446 | #define PT_REGS_PARM1(x) ((x)->regs[4]) 447 | #define PT_REGS_PARM2(x) ((x)->regs[5]) 448 | #define PT_REGS_PARM3(x) ((x)->regs[6]) 449 | #define PT_REGS_PARM4(x) ((x)->regs[7]) 450 | #define PT_REGS_PARM5(x) ((x)->regs[8]) 451 | #define PT_REGS_RET(x) ((x)->regs[31]) 452 | #define PT_REGS_FP(x) ((x)->regs[30]) /* Works only with CONFIG_FRAME_POINTER */ 453 | #define PT_REGS_RC(x) ((x)->regs[1]) 454 | #define PT_REGS_SP(x) ((x)->regs[29]) 455 | #define PT_REGS_IP(x) ((x)->cp0_epc) 456 | 457 | #elif defined(bpf_target_powerpc) 458 | 459 | #define PT_REGS_PARM1(x) ((x)->gpr[3]) 460 | #define PT_REGS_PARM2(x) ((x)->gpr[4]) 461 | #define PT_REGS_PARM3(x) ((x)->gpr[5]) 462 | #define PT_REGS_PARM4(x) ((x)->gpr[6]) 463 | #define PT_REGS_PARM5(x) ((x)->gpr[7]) 464 | #define PT_REGS_RC(x) ((x)->gpr[3]) 465 | #define PT_REGS_SP(x) ((x)->sp) 466 | #define PT_REGS_IP(x) ((x)->nip) 467 | 468 | #elif defined(bpf_target_sparc) 469 | 470 | #define PT_REGS_PARM1(x) ((x)->u_regs[UREG_I0]) 471 | #define PT_REGS_PARM2(x) ((x)->u_regs[UREG_I1]) 472 | #define PT_REGS_PARM3(x) ((x)->u_regs[UREG_I2]) 473 | #define PT_REGS_PARM4(x) ((x)->u_regs[UREG_I3]) 474 | #define PT_REGS_PARM5(x) ((x)->u_regs[UREG_I4]) 475 | #define PT_REGS_RET(x) ((x)->u_regs[UREG_I7]) 476 | #define PT_REGS_RC(x) ((x)->u_regs[UREG_I0]) 477 | #define PT_REGS_SP(x) ((x)->u_regs[UREG_FP]) 478 | 479 | /* Should this also be a bpf_target check for the sparc case? */ 480 | #if defined(__arch64__) 481 | #define PT_REGS_IP(x) ((x)->tpc) 482 | #else 483 | #define PT_REGS_IP(x) ((x)->pc) 484 | #endif 485 | 486 | #endif 487 | 488 | #if defined(bpf_target_powerpc) 489 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) 490 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP 491 | #elif defined(bpf_target_sparc) 492 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = PT_REGS_RET(ctx); }) 493 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP 494 | #else 495 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ \ 496 | bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) 497 | #define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ \ 498 | bpf_probe_read(&(ip), sizeof(ip), \ 499 | (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) 500 | #endif 501 | 502 | /* 503 | * BPF_CORE_READ abstracts away bpf_probe_read() call and captures offset 504 | * relocation for source address using __builtin_preserve_access_index() 505 | * built-in, provided by Clang. 506 | * 507 | * __builtin_preserve_access_index() takes as an argument an expression of 508 | * taking an address of a field within struct/union. It makes compiler emit 509 | * a relocation, which records BTF type ID describing root struct/union and an 510 | * accessor string which describes exact embedded field that was used to take 511 | * an address. See detailed description of this relocation format and 512 | * semantics in comments to struct bpf_offset_reloc in libbpf_internal.h. 513 | * 514 | * This relocation allows libbpf to adjust BPF instruction to use correct 515 | * actual field offset, based on target kernel BTF type that matches original 516 | * (local) BTF, used to record relocation. 517 | */ 518 | #define BPF_CORE_READ(dst, src) \ 519 | bpf_probe_read((dst), sizeof(*(src)), \ 520 | __builtin_preserve_access_index(src)) 521 | 522 | #endif 523 | -------------------------------------------------------------------------------- /ebpf/bpf/bpf_map.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | /* Copyright (c) 2020 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of version 2 of the GNU General Public 6 | * License as published by the Free Software Foundation. 7 | */ 8 | #define BUF_SIZE_MAP_NS 256 9 | 10 | typedef struct bpf_map_def { 11 | unsigned int type; 12 | unsigned int key_size; 13 | unsigned int value_size; 14 | unsigned int max_entries; 15 | unsigned int map_flags; 16 | unsigned int inner_map_idx; 17 | unsigned int pinning; 18 | char namespace[BUF_SIZE_MAP_NS]; 19 | } bpf_map_def; 20 | 21 | enum bpf_pin_type { 22 | PIN_NONE = 0, 23 | PIN_OBJECT_NS, 24 | PIN_GLOBAL_NS, 25 | PIN_CUSTOM_NS, 26 | }; 27 | -------------------------------------------------------------------------------- /ebpf/main.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | /* Copyright (c) 2020 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of version 2 of the GNU General Public 6 | * License as published by the Free Software Foundation. 7 | */ 8 | #pragma clang diagnostic push 9 | #pragma clang diagnostic ignored "-Waddress-of-packed-member" 10 | #pragma clang diagnostic ignored "-Warray-bounds" 11 | #pragma clang diagnostic ignored "-Wunused-label" 12 | #pragma clang diagnostic ignored "-Wgnu-variable-sized-type-not-at-end" 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | /* In Linux 5.4 asm_inline was introduced, but it's not supported by clang. 22 | * Redefine it to just asm to enable successful compilation. 23 | */ 24 | #ifdef asm_inline 25 | #undef asm_inline 26 | #define asm_inline asm 27 | #endif 28 | /* Before bpf_helpers.h is included, uapi bpf.h has been 29 | * included, which references linux/types.h. This may bring 30 | * in asm_volatile_goto definition if permitted based on 31 | * compiler setup and kernel configs. 32 | * 33 | * clang does not support "asm volatile goto" yet. 34 | * So redefine asm_volatile_goto to some invalid asm code. 35 | * If asm_volatile_goto is actually used by the bpf program, 36 | * a compilation error will appear. 37 | */ 38 | #ifdef asm_volatile_goto 39 | #undef asm_volatile_goto 40 | #endif 41 | #define asm_volatile_goto(x...) asm volatile("invalid use of asm_volatile_goto") 42 | #pragma clang diagnostic pop 43 | 44 | // Custom eBPF helpers 45 | #include "bpf/bpf.h" 46 | #include "bpf/bpf_map.h" 47 | #include "bpf/bpf_helpers.h" 48 | 49 | // ebpfkit-monitor probes 50 | #include "monitor/defs.h" 51 | #include "monitor/context.h" 52 | #include "monitor/bpf.h" 53 | #include "monitor/exec.h" 54 | 55 | char _license[] SEC("license") = "GPL"; 56 | __u32 _version SEC("version") = 0xFFFFFFFE; 57 | -------------------------------------------------------------------------------- /ebpf/monitor/bpf.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | /* Copyright (c) 2020 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of version 2 of the GNU General Public 6 | * License as published by the Free Software Foundation. 7 | */ 8 | #ifndef _BPF_H_ 9 | #define _BPF_H_ 10 | 11 | __attribute__((always_inline)) static u64 load_protect_bpf() { 12 | u64 protect_bpf = 0; 13 | LOAD_CONSTANT("protect_bpf", protect_bpf); 14 | return protect_bpf; 15 | } 16 | 17 | SYSCALL_KPROBE3(bpf, int, cmd, union bpf_attr *, uattr, unsigned int, size) { 18 | u32 tgid = bpf_get_current_pid_tgid() >> 32; 19 | 20 | // check if the current process is allowed to use the bpf syscall 21 | u32 *cookie = bpf_map_lookup_elem(&tgid_cookie, &tgid); 22 | if (cookie == NULL) { 23 | if (load_protect_bpf() == 1) { 24 | bpf_override_return(ctx, -EPERM); 25 | } 26 | return 0; 27 | } 28 | return 0; 29 | } 30 | 31 | __attribute__((always_inline)) void save_obj_fd(struct bpf_context_t *bpf_ctx) { 32 | struct tgid_fd_t key = { 33 | .tgid = bpf_get_current_pid_tgid() >> 32, 34 | .fd = bpf_ctx->retval, 35 | }; 36 | 37 | switch (bpf_ctx->cmd) { 38 | case BPF_MAP_CREATE: 39 | case BPF_MAP_GET_FD_BY_ID: 40 | bpf_map_update_elem(&tgid_fd_map_id, &key, &bpf_ctx->map_id, BPF_ANY); 41 | break; 42 | case BPF_PROG_LOAD: 43 | case BPF_PROG_GET_FD_BY_ID: 44 | bpf_map_update_elem(&tgid_fd_prog_id, &key, &bpf_ctx->prog_id, BPF_ANY); 45 | break; 46 | } 47 | } 48 | 49 | __attribute__((always_inline)) u32 fetch_map_id(int fd) { 50 | struct tgid_fd_t key = { 51 | .tgid = bpf_get_current_pid_tgid() >> 32, 52 | .fd = fd, 53 | }; 54 | 55 | u32 *map_id = bpf_map_lookup_elem(&tgid_fd_map_id, &key); 56 | if (map_id == NULL) { 57 | return 0; 58 | } 59 | return *map_id; 60 | } 61 | 62 | __attribute__((always_inline)) u32 fetch_prog_id(int fd) { 63 | struct tgid_fd_t key = { 64 | .tgid = bpf_get_current_pid_tgid() >> 32, 65 | .fd = fd, 66 | }; 67 | 68 | u32 *map_id = bpf_map_lookup_elem(&tgid_fd_prog_id, &key); 69 | if (map_id == NULL) { 70 | return 0; 71 | } 72 | return *map_id; 73 | } 74 | 75 | __attribute__((always_inline)) void populate_map_id_and_prog_id(struct bpf_context_t *bpf_ctx) { 76 | switch (bpf_ctx->cmd) { 77 | case BPF_MAP_LOOKUP_ELEM: 78 | case BPF_MAP_UPDATE_ELEM: 79 | case BPF_MAP_DELETE_ELEM: 80 | case BPF_MAP_LOOKUP_AND_DELETE_ELEM: 81 | case BPF_MAP_GET_NEXT_KEY: 82 | case BPF_MAP_FREEZE: 83 | bpf_ctx->map_id = fetch_map_id(bpf_ctx->attr.map_fd); 84 | break; 85 | case BPF_PROG_ATTACH: 86 | bpf_ctx->prog_id = fetch_prog_id(bpf_ctx->attr.attach_bpf_fd); 87 | break; 88 | case BPF_PROG_DETACH: 89 | bpf_ctx->prog_id = fetch_prog_id(bpf_ctx->attr.target_fd); 90 | break; 91 | case BPF_PROG_QUERY: 92 | bpf_ctx->prog_id = fetch_prog_id(bpf_ctx->attr.query.target_fd); 93 | break; 94 | case BPF_PROG_TEST_RUN: 95 | bpf_ctx->prog_id = fetch_prog_id(bpf_ctx->attr.test.prog_fd); 96 | break; 97 | case BPF_PROG_GET_NEXT_ID: 98 | bpf_ctx->prog_id = bpf_ctx->attr.start_id; 99 | break; 100 | case BPF_MAP_GET_NEXT_ID: 101 | bpf_ctx->map_id = bpf_ctx->attr.start_id; 102 | break; 103 | case BPF_OBJ_GET_INFO_BY_FD: 104 | bpf_ctx->map_id = fetch_map_id(bpf_ctx->attr.info.bpf_fd); 105 | bpf_ctx->prog_id = fetch_prog_id(bpf_ctx->attr.info.bpf_fd); 106 | break; 107 | case BPF_OBJ_PIN: 108 | bpf_ctx->map_id = fetch_map_id(bpf_ctx->attr.bpf_fd); 109 | bpf_ctx->prog_id = fetch_prog_id(bpf_ctx->attr.bpf_fd); 110 | break; 111 | case BPF_RAW_TRACEPOINT_OPEN: 112 | bpf_ctx->prog_id = fetch_prog_id(bpf_ctx->attr.raw_tracepoint.prog_fd); 113 | break; 114 | case BPF_TASK_FD_QUERY: 115 | bpf_ctx->prog_id = fetch_prog_id(bpf_ctx->attr.task_fd_query.fd); 116 | break; 117 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0) 118 | case BPF_MAP_LOOKUP_BATCH: 119 | case BPF_MAP_LOOKUP_AND_DELETE_BATCH: 120 | case BPF_MAP_UPDATE_BATCH: 121 | case BPF_MAP_DELETE_BATCH: 122 | bpf_ctx->map_id = fetch_map_id(bpf_ctx->attr.batch.map_fd); 123 | break; 124 | #endif 125 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0) 126 | case BPF_LINK_CREATE: 127 | bpf_ctx->prog_id = fetch_prog_id(bpf_ctx->attr.link_create.prog_fd); 128 | break; 129 | case BPF_LINK_UPDATE: 130 | bpf_ctx->prog_id = fetch_prog_id(bpf_ctx->attr.link_update.old_prog_fd); 131 | break; 132 | #endif 133 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) 134 | case BPF_PROG_BIND_MAP: 135 | bpf_ctx->map_id = fetch_map_id(bpf_ctx->attr.prog_bind_map.map_fd); 136 | bpf_ctx->prog_id = fetch_prog_id(bpf_ctx->attr.prog_bind_map.prog_fd); 137 | break; 138 | #endif 139 | } 140 | } 141 | 142 | __attribute__((always_inline)) void send_event(struct pt_regs *ctx, struct bpf_context_t *bpf_ctx) { 143 | struct bpf_event_t evt = { 144 | .timestamp = bpf_ktime_get_ns(), 145 | .cmd = bpf_ctx->cmd, 146 | }; 147 | bpf_get_current_comm(&evt.comm, sizeof(evt.comm)); 148 | 149 | // select map if applicable 150 | if (bpf_ctx->map_id != 0) { 151 | struct map_t *map = bpf_map_lookup_elem(&bpf_maps, &bpf_ctx->map_id); 152 | if (map != NULL) { 153 | evt.map = *map; 154 | // bpf_printk("cmd:%d map:%s\n", bpf_ctx->cmd, evt.map.name); 155 | } 156 | } 157 | 158 | // select prog if applicable 159 | if (bpf_ctx->prog_id != 0) { 160 | struct prog_t *prog = bpf_map_lookup_elem(&bpf_progs, &bpf_ctx->prog_id); 161 | if (prog != NULL) { 162 | evt.prog = *prog; 163 | // bpf_printk("cmd:%d prog:%s helpers:%lu\n", bpf_ctx->cmd, evt.prog.name, bpf_ctx->helpers[0]); 164 | } 165 | } 166 | 167 | // send event 168 | u64 cpu = bpf_get_smp_processor_id(); 169 | bpf_perf_event_output(ctx, &events, cpu, &evt, sizeof(evt)); 170 | return; 171 | } 172 | 173 | SYSCALL_KRETPROBE(bpf) { 174 | struct bpf_context_t *bpf_ctx = get_ctx(); 175 | if (bpf_ctx == NULL) { 176 | // should never happen 177 | return 0; 178 | } 179 | bpf_ctx->retval = (int)PT_REGS_RC(ctx); 180 | 181 | // save file descriptor <-> map_id mapping if applicable 182 | if (bpf_ctx->map_id != 0 || bpf_ctx->prog_id != 0) { 183 | save_obj_fd(bpf_ctx); 184 | } 185 | 186 | // populate map_id or prog_id if applicable 187 | populate_map_id_and_prog_id(bpf_ctx); 188 | 189 | // send monitoring event 190 | send_event(ctx, bpf_ctx); 191 | return 0; 192 | } 193 | 194 | SEC("kprobe/security_bpf") 195 | int kprobe_security_bpf(struct pt_regs *ctx) { 196 | struct bpf_context_t *bpf_ctx = reset_ctx(); 197 | if (bpf_ctx == NULL) { 198 | // should never happen 199 | return 0; 200 | } 201 | 202 | bpf_ctx->cmd = (int)PT_REGS_PARM1(ctx); 203 | bpf_probe_read(&bpf_ctx->attr, sizeof(bpf_ctx->attr), (union bpf_attr *)PT_REGS_PARM2(ctx)); 204 | return 0; 205 | } 206 | 207 | SEC("kprobe/security_bpf_map") 208 | int kprobe_security_bpf_map(struct pt_regs *ctx) { 209 | struct bpf_map *map = (struct bpf_map *)PT_REGS_PARM1(ctx); 210 | 211 | // collect relevant map metadata 212 | struct map_t m = {}; 213 | bpf_probe_read(&m.id, sizeof(m.id), &map->id); 214 | bpf_probe_read(&m.name, sizeof(m.name), &map->name); 215 | bpf_probe_read(&m.map_type, sizeof(m.map_type), &map->map_type); 216 | 217 | // save map metadata 218 | bpf_map_update_elem(&bpf_maps, &m.id, &m, BPF_ANY); 219 | 220 | // update context 221 | struct bpf_context_t *bpf_ctx = get_ctx(); 222 | if (bpf_ctx == NULL) { 223 | // should never happen 224 | return 0; 225 | } 226 | bpf_ctx->map_id = m.id; 227 | return 0; 228 | } 229 | 230 | SEC("kprobe/security_bpf_prog") 231 | int kprobe_security_bpf_prg(struct pt_regs *ctx) { 232 | struct bpf_prog *prog = (struct bpf_prog *)PT_REGS_PARM1(ctx); 233 | struct bpf_prog_aux *prog_aux = 0; 234 | bpf_probe_read(&prog_aux, sizeof(prog_aux), &prog->aux); 235 | 236 | // collect relevant prog metadata 237 | struct prog_t p = {}; 238 | bpf_probe_read(&p.id, sizeof(p.id), &prog_aux->id); 239 | bpf_probe_read(&p.prog_type, sizeof(p.prog_type), &prog->type); 240 | bpf_probe_read(&p.attach_type, sizeof(p.attach_type), &prog->expected_attach_type); 241 | bpf_probe_read(&p.name, sizeof(p.name), &prog_aux->name); 242 | 243 | // update context 244 | struct bpf_context_t *bpf_ctx = get_ctx(); 245 | if (bpf_ctx == NULL) { 246 | // should never happen 247 | return 0; 248 | } 249 | bpf_ctx->prog_id = p.id; 250 | 251 | // add prog helpers 252 | p.helpers[0] = bpf_ctx->helpers[0]; 253 | p.helpers[1] = bpf_ctx->helpers[1]; 254 | p.helpers[2] = bpf_ctx->helpers[2]; 255 | 256 | // save prog metadata 257 | bpf_map_update_elem(&bpf_progs, &p.id, &p, BPF_ANY); 258 | return 0; 259 | } 260 | 261 | SEC("kprobe/check_helper_call") 262 | int kprobe_check_helper_call(struct pt_regs *ctx) { 263 | int func_id = 0; 264 | struct bpf_context_t *bpf_ctx = get_ctx(); 265 | if (bpf_ctx == NULL) { 266 | // should never happen 267 | return 0; 268 | } 269 | 270 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,13,0) 271 | struct bpf_insn *insn = (struct bpf_insn *)PT_REGS_PARM2(ctx); 272 | bpf_probe_read(&func_id, sizeof(func_id), &insn->imm); 273 | #else 274 | func_id = (int)PT_REGS_PARM2(ctx); 275 | #endif 276 | 277 | if (func_id >= 128) { 278 | bpf_ctx->helpers[2] |= (u64) 1 << (func_id - 128); 279 | } else if (func_id >= 64) { 280 | bpf_ctx->helpers[1] |= (u64) 1 << (func_id - 64); 281 | } else if (func_id >= 0) { 282 | bpf_ctx->helpers[0] |= (u64) 1 << (func_id); 283 | } 284 | return 0; 285 | } 286 | 287 | #endif -------------------------------------------------------------------------------- /ebpf/monitor/context.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | /* Copyright (c) 2020 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of version 2 of the GNU General Public 6 | * License as published by the Free Software Foundation. 7 | */ 8 | #ifndef _CONTEXT_H_ 9 | #define _CONTEXT_H_ 10 | 11 | struct bpf_context_t { 12 | int cmd; 13 | u32 map_id; 14 | u32 prog_id; 15 | int retval; 16 | u64 helpers[3]; 17 | union bpf_attr attr; 18 | }; 19 | 20 | struct bpf_map_def SEC("maps/bpf_context") bpf_context = { 21 | .type = BPF_MAP_TYPE_LRU_HASH, 22 | .key_size = sizeof(u64), 23 | .value_size = sizeof(struct bpf_context_t), 24 | .max_entries = 4096, 25 | .pinning = 0, 26 | .namespace = "", 27 | }; 28 | 29 | struct bpf_map_def SEC("maps/bpf_context_gen") bpf_context_gen = { 30 | .type = BPF_MAP_TYPE_ARRAY, 31 | .key_size = sizeof(u32), 32 | .value_size = sizeof(struct bpf_context_t), 33 | .max_entries = 1, 34 | .pinning = 0, 35 | .namespace = "", 36 | }; 37 | 38 | // reset_context resets and return the context associated to the current thread 39 | __attribute__((always_inline)) struct bpf_context_t *reset_ctx() { 40 | u32 key_gen = 0; 41 | struct bpf_context_t *bpf_ctx = bpf_map_lookup_elem(&bpf_context_gen, &key_gen); 42 | if (bpf_ctx == NULL) { 43 | // should never happen 44 | return 0; 45 | } 46 | 47 | u64 id = bpf_get_current_pid_tgid(); 48 | bpf_map_update_elem(&bpf_context, &id, bpf_ctx, BPF_ANY); 49 | return bpf_map_lookup_elem(&bpf_context, &id); 50 | } 51 | 52 | // get_context returns the current context associated to the current thread 53 | __attribute__((always_inline)) struct bpf_context_t *get_ctx() { 54 | u64 id = bpf_get_current_pid_tgid(); 55 | return bpf_map_lookup_elem(&bpf_context, &id); 56 | } 57 | 58 | #endif -------------------------------------------------------------------------------- /ebpf/monitor/defs.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | /* Copyright (c) 2020 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of version 2 of the GNU General Public 6 | * License as published by the Free Software Foundation. 7 | */ 8 | #ifndef _DEFS_H_ 9 | #define _DEFS_H_ 10 | 11 | #define LOAD_CONSTANT(param, var) asm("%0 = " param " ll" : "=r"(var)) 12 | 13 | #if defined(__x86_64__) 14 | #define SYSCALL64_PREFIX "__x64_" 15 | #define SYSCALL32_PREFIX "__ia32_" 16 | 17 | #define SYSCALL64_PT_REGS_PARM1(x) ((x)->di) 18 | #define SYSCALL64_PT_REGS_PARM2(x) ((x)->si) 19 | #define SYSCALL64_PT_REGS_PARM3(x) ((x)->dx) 20 | #if USE_SYSCALL_WRAPPER == 1 21 | #define SYSCALL64_PT_REGS_PARM4(x) ((x)->r10) 22 | #else 23 | #define SYSCALL64_PT_REGS_PARM4(x) ((x)->cx) 24 | #endif 25 | #define SYSCALL64_PT_REGS_PARM5(x) ((x)->r8) 26 | #define SYSCALL64_PT_REGS_PARM6(x) ((x)->r9) 27 | 28 | #define SYSCALL32_PT_REGS_PARM1(x) ((x)->bx) 29 | #define SYSCALL32_PT_REGS_PARM2(x) ((x)->cx) 30 | #define SYSCALL32_PT_REGS_PARM3(x) ((x)->dx) 31 | #define SYSCALL32_PT_REGS_PARM4(x) ((x)->si) 32 | #define SYSCALL32_PT_REGS_PARM5(x) ((x)->di) 33 | #define SYSCALL32_PT_REGS_PARM6(x) ((x)->bp) 34 | 35 | #elif defined(__aarch64__) 36 | #define SYSCALL64_PREFIX "__arm64_" 37 | #define SYSCALL32_PREFIX "__arm32_" 38 | 39 | #define SYSCALL64_PT_REGS_PARM1(x) PT_REGS_PARM1(x) 40 | #define SYSCALL64_PT_REGS_PARM2(x) PT_REGS_PARM2(x) 41 | #define SYSCALL64_PT_REGS_PARM3(x) PT_REGS_PARM3(x) 42 | #define SYSCALL64_PT_REGS_PARM4(x) PT_REGS_PARM4(x) 43 | #define SYSCALL64_PT_REGS_PARM5(x) PT_REGS_PARM5(x) 44 | #define SYSCALL64_PT_REGS_PARM6(x) PT_REGS_PARM6(x) 45 | 46 | #define SYSCALL32_PT_REGS_PARM1(x) PT_REGS_PARM1(x) 47 | #define SYSCALL32_PT_REGS_PARM2(x) PT_REGS_PARM2(x) 48 | #define SYSCALL32_PT_REGS_PARM3(x) PT_REGS_PARM3(x) 49 | #define SYSCALL32_PT_REGS_PARM4(x) PT_REGS_PARM4(x) 50 | #define SYSCALL32_PT_REGS_PARM5(x) PT_REGS_PARM5(x) 51 | #define SYSCALL32_PT_REGS_PARM6(x) PT_REGS_PARM6(x) 52 | 53 | #else 54 | #error "Unsupported platform" 55 | #endif 56 | 57 | /* 58 | * __MAP - apply a macro to syscall arguments 59 | * __MAP(n, m, t1, a1, t2, a2, ..., tn, an) will expand to 60 | * m(t1, a1), m(t2, a2), ..., m(tn, an) 61 | * The first argument must be equal to the amount of type/name 62 | * pairs given. Note that this list of pairs (i.e. the arguments 63 | * of __MAP starting at the third one) is in the same format as 64 | * for SYSCALL_DEFINE/COMPAT_SYSCALL_DEFINE 65 | */ 66 | #define __JOIN0(m,...) 67 | #define __JOIN1(m,t,a,...) ,m(t,a) 68 | #define __JOIN2(m,t,a,...) ,m(t,a) __JOIN1(m,__VA_ARGS__) 69 | #define __JOIN3(m,t,a,...) ,m(t,a) __JOIN2(m,__VA_ARGS__) 70 | #define __JOIN4(m,t,a,...) ,m(t,a) __JOIN3(m,__VA_ARGS__) 71 | #define __JOIN5(m,t,a,...) ,m(t,a) __JOIN4(m,__VA_ARGS__) 72 | #define __JOIN6(m,t,a,...) ,m(t,a) __JOIN5(m,__VA_ARGS__) 73 | #define __JOIN(n,...) __JOIN##n(__VA_ARGS__) 74 | 75 | #define __MAP0(n,m,...) 76 | #define __MAP1(n,m,t1,a1,...) m(1,t1,a1) 77 | #define __MAP2(n,m,t1,a1,t2,a2) m(1,t1,a1) m(2,t2,a2) 78 | #define __MAP3(n,m,t1,a1,t2,a2,t3,a3) m(1,t1,a1) m(2,t2,a2) m(3,t3,a3) 79 | #define __MAP4(n,m,t1,a1,t2,a2,t3,a3,t4,a4) m(1,t1,a1) m(2,t2,a2) m(3,t3,a3) m(4,t4,a4) 80 | #define __MAP5(n,m,t1,a1,t2,a2,t3,a3,t4,a4,t5,a5) m(1,t1,a1) m(2,t2,a2) m(3,t3,a3) m(4,t4,a4) m(5,t5,a5) 81 | #define __MAP6(n,m,t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6) m(1,t1,a1) m(2,t2,a2) m(3,t3,a3) m(4,t4,a4) m(5,t5,a5) m(6,t6,a6) 82 | #define __MAP(n,...) __MAP##n(n,__VA_ARGS__) 83 | 84 | #define __SC_DECL(t, a) t a 85 | #define __SC_PASS(t, a) a 86 | 87 | #define SYSCALL_ABI_HOOKx(x,word_size,type,TYPE,prefix,syscall,suffix,...) \ 88 | int __attribute__((always_inline)) type##__##sys##syscall(struct pt_regs *ctx __JOIN(x,__SC_DECL,__VA_ARGS__)); \ 89 | SEC(#type "/" SYSCALL##word_size##_PREFIX #prefix SYSCALL_PREFIX #syscall #suffix) \ 90 | int type##__ ##word_size##_##prefix ##sys##syscall##suffix(struct pt_regs *ctx) { \ 91 | SYSCALL_##TYPE##_PROLOG(x,__SC_##word_size##_PARAM,syscall,__VA_ARGS__) \ 92 | return type##__sys##syscall(ctx __JOIN(x,__SC_PASS,__VA_ARGS__)); \ 93 | } 94 | 95 | #define SYSCALL_HOOK_COMMON(x,type,syscall,...) int __attribute__((always_inline)) type##__sys##syscall(struct pt_regs *ctx __JOIN(x,__SC_DECL,__VA_ARGS__)) 96 | 97 | #if USE_SYSCALL_WRAPPER == 1 98 | #define SYSCALL_PREFIX "sys" 99 | #define __SC_64_PARAM(n, t, a) t a; bpf_probe_read(&a, sizeof(t), (void*) &SYSCALL64_PT_REGS_PARM##n(rctx)); 100 | #define __SC_32_PARAM(n, t, a) t a; bpf_probe_read(&a, sizeof(t), (void*) &SYSCALL32_PT_REGS_PARM##n(rctx)); 101 | #define SYSCALL_KPROBE_PROLOG(x,m,syscall,...) \ 102 | struct pt_regs *rctx = (struct pt_regs *) PT_REGS_PARM1(ctx); \ 103 | if (!rctx) return 0; \ 104 | __MAP(x,m,__VA_ARGS__) 105 | #define SYSCALL_KRETPROBE_PROLOG(...) 106 | #define SYSCALL_HOOKx(x,type,TYPE,prefix,name,...) \ 107 | SYSCALL_ABI_HOOKx(x,32,type,TYPE,prefix,name,,__VA_ARGS__) \ 108 | SYSCALL_ABI_HOOKx(x,64,type,TYPE,,name,,__VA_ARGS__) \ 109 | SYSCALL_HOOK_COMMON(x,type,name,__VA_ARGS__) 110 | #define SYSCALL_COMPAT_HOOKx(x,type,TYPE,name,...) \ 111 | SYSCALL_ABI_HOOKx(x,32,type,TYPE,compat_,name,,__VA_ARGS__) \ 112 | SYSCALL_ABI_HOOKx(x,64,type,TYPE,,name,,__VA_ARGS__) \ 113 | SYSCALL_HOOK_COMMON(x,type,name,__VA_ARGS__) 114 | #define SYSCALL_COMPAT_TIME_HOOKx(x,type,TYPE,name,...) \ 115 | SYSCALL_ABI_HOOKx(x,32,type,TYPE,compat_,name,,__VA_ARGS__) \ 116 | SYSCALL_ABI_HOOKx(x,32,type,TYPE,,name,_time32,__VA_ARGS__) \ 117 | SYSCALL_ABI_HOOKx(x,64,type,TYPE,,name,,__VA_ARGS__) \ 118 | SYSCALL_ABI_HOOKx(x,64,type,TYPE,,name,_time32,__VA_ARGS__) \ 119 | SYSCALL_HOOK_COMMON(x,type,name,__VA_ARGS__) 120 | #else 121 | #undef SYSCALL32_PREFIX 122 | #undef SYSCALL64_PREFIX 123 | #define SYSCALL32_PREFIX "" 124 | #define SYSCALL64_PREFIX "" 125 | #define SYSCALL_PREFIX "sys" 126 | #define __SC_64_PARAM(n, t, a) t a = (t) SYSCALL64_PT_REGS_PARM##n(ctx); 127 | #define __SC_32_PARAM(n, t, a) t a = (t) SYSCALL32_PT_REGS_PARM##n(ctx); 128 | #define SYSCALL_KPROBE_PROLOG(x,m,syscall,...) \ 129 | struct pt_regs *rctx = ctx; \ 130 | if (!rctx) return 0; \ 131 | __MAP(x,m,__VA_ARGS__) 132 | #define SYSCALL_KRETPROBE_PROLOG(...) 133 | #define SYSCALL_HOOKx(x,type,TYPE,prefix,name,...) \ 134 | SYSCALL_ABI_HOOKx(x,64,type,TYPE,compat_,name,,__VA_ARGS__) \ 135 | SYSCALL_ABI_HOOKx(x,64,type,TYPE,,name,,__VA_ARGS__) \ 136 | SYSCALL_HOOK_COMMON(x,type,name,__VA_ARGS__) 137 | #define SYSCALL_COMPAT_HOOKx(x,type,TYPE,name,...) \ 138 | SYSCALL_ABI_HOOKx(x,64,type,TYPE,compat_,name,,__VA_ARGS__) \ 139 | SYSCALL_ABI_HOOKx(x,64,type,TYPE,,name,,__VA_ARGS__) \ 140 | SYSCALL_HOOK_COMMON(x,type,name,__VA_ARGS__) 141 | #define SYSCALL_COMPAT_TIME_HOOKx(x,type,TYPE,name,...) \ 142 | SYSCALL_ABI_HOOKx(x,64,type,TYPE,compat_,name,,__VA_ARGS__) \ 143 | SYSCALL_ABI_HOOKx(x,64,type,TYPE,,name,,__VA_ARGS__) \ 144 | SYSCALL_HOOK_COMMON(x,type,name,__VA_ARGS__) 145 | #endif 146 | 147 | #define SYSCALL_KPROBE0(name, ...) SYSCALL_HOOKx(0,kprobe,KPROBE,,_##name,__VA_ARGS__) 148 | #define SYSCALL_KPROBE1(name, ...) SYSCALL_HOOKx(1,kprobe,KPROBE,,_##name,__VA_ARGS__) 149 | #define SYSCALL_KPROBE2(name, ...) SYSCALL_HOOKx(2,kprobe,KPROBE,,_##name,__VA_ARGS__) 150 | #define SYSCALL_KPROBE3(name, ...) SYSCALL_HOOKx(3,kprobe,KPROBE,,_##name,__VA_ARGS__) 151 | #define SYSCALL_KPROBE4(name, ...) SYSCALL_HOOKx(4,kprobe,KPROBE,,_##name,__VA_ARGS__) 152 | #define SYSCALL_KPROBE5(name, ...) SYSCALL_HOOKx(5,kprobe,KPROBE,,_##name,__VA_ARGS__) 153 | #define SYSCALL_KPROBE6(name, ...) SYSCALL_HOOKx(6,kprobe,KPROBE,,_##name,__VA_ARGS__) 154 | 155 | #define SYSCALL_KRETPROBE(name, ...) SYSCALL_HOOKx(0,kretprobe,KRETPROBE,,_##name) 156 | 157 | #define SYSCALL_COMPAT_KPROBE0(name, ...) SYSCALL_COMPAT_HOOKx(0,kprobe,KPROBE,_##name,__VA_ARGS__) 158 | #define SYSCALL_COMPAT_KPROBE1(name, ...) SYSCALL_COMPAT_HOOKx(1,kprobe,KPROBE,_##name,__VA_ARGS__) 159 | #define SYSCALL_COMPAT_KPROBE2(name, ...) SYSCALL_COMPAT_HOOKx(2,kprobe,KPROBE,_##name,__VA_ARGS__) 160 | #define SYSCALL_COMPAT_KPROBE3(name, ...) SYSCALL_COMPAT_HOOKx(3,kprobe,KPROBE,_##name,__VA_ARGS__) 161 | #define SYSCALL_COMPAT_KPROBE4(name, ...) SYSCALL_COMPAT_HOOKx(4,kprobe,KPROBE,_##name,__VA_ARGS__) 162 | #define SYSCALL_COMPAT_KPROBE5(name, ...) SYSCALL_COMPAT_HOOKx(5,kprobe,KPROBE,_##name,__VA_ARGS__) 163 | #define SYSCALL_COMPAT_KPROBE6(name, ...) SYSCALL_COMPAT_HOOKx(6,kprobe,KPROBE,_##name,__VA_ARGS__) 164 | 165 | #define SYSCALL_COMPAT_KRETPROBE(name, ...) SYSCALL_COMPAT_HOOKx(0,kretprobe,KRETPROBE,_##name) 166 | 167 | #define SYSCALL_COMPAT_TIME_KPROBE0(name, ...) SYSCALL_COMPAT_TIME_HOOKx(0,kprobe,KPROBE,_##name,__VA_ARGS__) 168 | #define SYSCALL_COMPAT_TIME_KPROBE1(name, ...) SYSCALL_COMPAT_TIME_HOOKx(1,kprobe,KPROBE,_##name,__VA_ARGS__) 169 | #define SYSCALL_COMPAT_TIME_KPROBE2(name, ...) SYSCALL_COMPAT_TIME_HOOKx(2,kprobe,KPROBE,_##name,__VA_ARGS__) 170 | #define SYSCALL_COMPAT_TIME_KPROBE3(name, ...) SYSCALL_COMPAT_TIME_HOOKx(3,kprobe,KPROBE,_##name,__VA_ARGS__) 171 | #define SYSCALL_COMPAT_TIME_KPROBE4(name, ...) SYSCALL_COMPAT_TIME_HOOKx(4,kprobe,KPROBE,_##name,__VA_ARGS__) 172 | #define SYSCALL_COMPAT_TIME_KPROBE5(name, ...) SYSCALL_COMPAT_TIME_HOOKx(5,kprobe,KPROBE,_##name,__VA_ARGS__) 173 | #define SYSCALL_COMPAT_TIME_KPROBE6(name, ...) SYSCALL_COMPAT_TIME_HOOKx(6,kprobe,KPROBE,_##name,__VA_ARGS__) 174 | 175 | #define SYSCALL_COMPAT_TIME_KRETPROBE(name, ...) SYSCALL_COMPAT_TIME_HOOKx(0,kretprobe,KRETPROBE,_##name) 176 | 177 | #define PATH_MAX_LEN 350 178 | 179 | struct path_t { 180 | char filename[PATH_MAX_LEN]; 181 | }; 182 | 183 | struct bpf_map_def SEC("maps/allowed_binaries") allowed_binaries = { 184 | .type = BPF_MAP_TYPE_LRU_HASH, 185 | .key_size = sizeof(struct path_t), 186 | .value_size = sizeof(u32), 187 | .max_entries = 1024, 188 | .pinning = 0, 189 | .namespace = "", 190 | }; 191 | 192 | struct bpf_map_def SEC("maps/allowed_cookies") allowed_cookies = { 193 | .type = BPF_MAP_TYPE_LRU_HASH, 194 | .key_size = sizeof(u32), 195 | .value_size = sizeof(u32), 196 | .max_entries = 1024, 197 | .pinning = 0, 198 | .namespace = "", 199 | }; 200 | 201 | struct bpf_map_def SEC("maps/tgid_cookie") tgid_cookie = { 202 | .type = BPF_MAP_TYPE_LRU_HASH, 203 | .key_size = sizeof(u32), 204 | .value_size = sizeof(u32), 205 | .max_entries = 1024, 206 | .pinning = 0, 207 | .namespace = "", 208 | }; 209 | 210 | struct map_t { 211 | u32 id; 212 | enum bpf_map_type map_type; 213 | char name[BPF_OBJ_NAME_LEN]; 214 | }; 215 | 216 | struct bpf_map_def SEC("maps/bpf_maps") bpf_maps = { 217 | .type = BPF_MAP_TYPE_LRU_HASH, 218 | .key_size = sizeof(u32), 219 | .value_size = sizeof(struct map_t), 220 | .max_entries = 4096, 221 | .pinning = 0, 222 | .namespace = "", 223 | }; 224 | 225 | struct prog_t { 226 | u32 id; 227 | enum bpf_prog_type prog_type; 228 | enum bpf_attach_type attach_type; 229 | u32 padding; 230 | u64 helpers[3]; 231 | char name[BPF_OBJ_NAME_LEN]; 232 | }; 233 | 234 | struct bpf_map_def SEC("maps/bpf_progs") bpf_progs = { 235 | .type = BPF_MAP_TYPE_LRU_HASH, 236 | .key_size = sizeof(u32), 237 | .value_size = sizeof(struct prog_t), 238 | .max_entries = 4096, 239 | .pinning = 0, 240 | .namespace = "", 241 | }; 242 | 243 | struct tgid_fd_t { 244 | u32 tgid; 245 | u32 fd; 246 | }; 247 | 248 | struct bpf_map_def SEC("maps/tgid_fd_map_id") tgid_fd_map_id = { 249 | .type = BPF_MAP_TYPE_LRU_HASH, 250 | .key_size = sizeof(struct tgid_fd_t), 251 | .value_size = sizeof(u32), 252 | .max_entries = 4096, 253 | .pinning = 0, 254 | .namespace = "", 255 | }; 256 | 257 | struct bpf_map_def SEC("maps/tgid_fd_prog_id") tgid_fd_prog_id = { 258 | .type = BPF_MAP_TYPE_LRU_HASH, 259 | .key_size = sizeof(struct tgid_fd_t), 260 | .value_size = sizeof(u32), 261 | .max_entries = 4096, 262 | .pinning = 0, 263 | .namespace = "", 264 | }; 265 | 266 | struct bpf_event_t { 267 | u64 timestamp; 268 | int cmd; 269 | u32 padding; 270 | struct map_t map; 271 | struct prog_t prog; 272 | char comm[TASK_COMM_LEN]; 273 | }; 274 | 275 | struct bpf_map_def SEC("maps/events") events = { 276 | .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, 277 | .key_size = sizeof(__u32), 278 | .value_size = sizeof(__u32), 279 | .max_entries = 0, 280 | .pinning = 0, 281 | .namespace = "", 282 | }; 283 | 284 | #endif 285 | -------------------------------------------------------------------------------- /ebpf/monitor/exec.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | /* Copyright (c) 2020 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of version 2 of the GNU General Public 6 | * License as published by the Free Software Foundation. 7 | */ 8 | #ifndef _EXEC_H_ 9 | #define _EXEC_H_ 10 | 11 | struct sched_process_exec_args 12 | { 13 | unsigned short common_type; 14 | unsigned char common_flags; 15 | unsigned char common_preempt_count; 16 | int common_pid; 17 | 18 | int data_loc_filename; 19 | pid_t pid; 20 | pid_t old_pid; 21 | }; 22 | 23 | SEC("tracepoint/sched/sched_process_exec") 24 | int tracepoint__sched__sched_process_exec(struct sched_process_exec_args *ctx) 25 | { 26 | unsigned short __offset = ctx->data_loc_filename & 0xFFFF; 27 | char *filename = (char *)ctx + __offset; 28 | struct path_t path = {}; 29 | bpf_probe_read_str(&path.filename, PATH_MAX_LEN, filename); 30 | 31 | u32 *match = bpf_map_lookup_elem(&allowed_binaries, &path.filename); 32 | if (match == NULL) { 33 | return 0; 34 | } 35 | 36 | // create new cookie for this binary 37 | u32 cookie = bpf_get_prandom_u32(); 38 | bpf_map_update_elem(&allowed_cookies, &cookie, &cookie, BPF_ANY); 39 | 40 | // set the cookie of the current tgid 41 | u32 tgid = bpf_get_current_pid_tgid() >> 32; 42 | bpf_map_update_elem(&tgid_cookie, &tgid, &cookie, BPF_ANY); 43 | return 0; 44 | }; 45 | 46 | struct sched_process_fork_args 47 | { 48 | unsigned short common_type; 49 | unsigned char common_flags; 50 | unsigned char common_preempt_count; 51 | int common_pid; 52 | 53 | char parent_comm[16]; 54 | pid_t parent_pid; 55 | char child_comm[16]; 56 | pid_t child_pid; 57 | }; 58 | 59 | SEC("tracepoint/sched/sched_process_fork") 60 | int tracepoint__sched__sched_process_fork(struct sched_process_fork_args *ctx) 61 | { 62 | u32 pid = bpf_get_current_pid_tgid(); 63 | 64 | // fetch parent cookie if it exists 65 | u32 *parent_cookie = bpf_map_lookup_elem(&tgid_cookie, &pid); 66 | if (parent_cookie == NULL) { 67 | // this process is not tracked, ignore 68 | return 0; 69 | } 70 | 71 | // The child pid here might be a tgid or a pid, ideally we'd only care about tgids, but since we expire the cookie 72 | // and not the tgid_cookie entries on exit, it doesn't matter. 73 | u32 child_id = (u32) ctx->child_pid; 74 | 75 | // inherit cookie 76 | u32 child_cookie = *parent_cookie; 77 | bpf_map_update_elem(&tgid_cookie, &child_id, &child_cookie, BPF_ANY); 78 | return 0; 79 | } 80 | 81 | struct sched_process_exit_args 82 | { 83 | unsigned short common_type; 84 | unsigned char common_flags; 85 | unsigned char common_preempt_count; 86 | int common_pid; 87 | 88 | char comm[16]; 89 | pid_t pid; 90 | int prio; 91 | }; 92 | 93 | SEC("tracepoint/sched/sched_process_exit") 94 | int tracepoint__sched__sched_process_exit(struct sched_process_exit_args *ctx) 95 | { 96 | u64 pid_tgid = bpf_get_current_pid_tgid(); 97 | u32 tgid = pid_tgid >> 32; 98 | u32 pid = pid_tgid; 99 | 100 | if (tgid == pid) { 101 | u32 *cookie = bpf_map_lookup_elem(&tgid_cookie, &tgid); 102 | if (cookie == NULL) { 103 | // this process is not tracked, ignore 104 | return 0; 105 | } 106 | 107 | // remove cookie 108 | u32 to_delete = *cookie; 109 | bpf_map_delete_elem(&allowed_cookies, &to_delete); 110 | } 111 | return 0; 112 | } 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/Gui774ume/ebpfkit-monitor 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/DataDog/ebpf v0.0.0-20210201234834-a101c2fadd02 7 | github.com/DataDog/gopsutil v0.0.0-20200624212600-1b53412ef321 8 | github.com/cobaugh/osrelease v0.0.0-20181218015638-a93a0a55a249 9 | github.com/pkg/errors v0.9.1 10 | github.com/shuLhan/go-bindata v4.0.0+incompatible 11 | github.com/sirupsen/logrus v1.7.0 12 | github.com/spf13/cobra v1.1.1 13 | golang.org/x/crypto v0.1.0 14 | golang.org/x/sys v0.1.0 15 | ) 16 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 6 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 7 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 8 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 9 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 10 | cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= 11 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 12 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 13 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 14 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 15 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 16 | github.com/DataDog/ebpf v0.0.0-20210201234834-a101c2fadd02 h1:PiVmjtxb2DHHRT8U4cFQLzhrDXQyXNan4Hr6RBghhqc= 17 | github.com/DataDog/ebpf v0.0.0-20210201234834-a101c2fadd02/go.mod h1:VSpIdBT/hwSbP3xKa5eYtiiBN2E37YePfTuyQVzSSig= 18 | github.com/DataDog/gopsutil v0.0.0-20200624212600-1b53412ef321 h1:OPAXA+r6yznoxWR5jQ2iTh5CvzIMrdw8AU0uFN2RwEw= 19 | github.com/DataDog/gopsutil v0.0.0-20200624212600-1b53412ef321/go.mod h1:tGQp6XG4XpOyy67WG/YWXVxzOY6LejK35e8KcQhtRIQ= 20 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 21 | github.com/StackExchange/wmi v0.0.0-20181212234831-e0a55b97c705 h1:UUppSQnhf4Yc6xGxSkoQpPhb7RVzuv5Nb1mwJ5VId9s= 22 | github.com/StackExchange/wmi v0.0.0-20181212234831-e0a55b97c705/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= 23 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 24 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 25 | github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= 26 | github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= 27 | github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 28 | github.com/avast/retry-go v2.7.0+incompatible h1:XaGnzl7gESAideSjr+I8Hki/JBi+Yb9baHlMRPeSC84= 29 | github.com/avast/retry-go v2.7.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= 30 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 31 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 32 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= 33 | github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= 34 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= 35 | github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575 h1:kHaBemcxl8o/pQ5VM1c8PVE1PubbNx3mjUr09OqWGCs= 36 | github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575/go.mod h1:9d6lWj8KzO/fd/NrVaLscBKmPigpZpn5YawRPw+e3Yo= 37 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 38 | github.com/cobaugh/osrelease v0.0.0-20181218015638-a93a0a55a249 h1:R0IDH8daQ3lODvu8YtxnIqqth5qMGCJyADoUQvmLx4o= 39 | github.com/cobaugh/osrelease v0.0.0-20181218015638-a93a0a55a249/go.mod h1:EHKW9yNEYSBpTKzuu7Y9oOrft/UlzH57rMIB03oev6M= 40 | github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= 41 | github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 42 | github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 43 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 44 | github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 45 | github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 46 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 47 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 48 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 49 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 50 | github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= 51 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 52 | github.com/florianl/go-tc v0.2.0 h1:k3Dr3rtmMP2KCRlWgRUC6XKBZA5lL9rNBAr80H50/6k= 53 | github.com/florianl/go-tc v0.2.0/go.mod h1:aWdDOHrIpaff8cZp6z7dgJZ1bRsgTS6pXIW0xRdFTK8= 54 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 55 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 56 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 57 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 58 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 59 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 60 | github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= 61 | github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= 62 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 63 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 64 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= 65 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 66 | github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 67 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 68 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 69 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 70 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 71 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 72 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 73 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 74 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 75 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 76 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 77 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 78 | github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= 79 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 80 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 81 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 82 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 83 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 84 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 85 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 86 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 87 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 88 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= 89 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 90 | github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= 91 | github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= 92 | github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= 93 | github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= 94 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 95 | github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 96 | github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= 97 | github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= 98 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 99 | github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= 100 | github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= 101 | github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= 102 | github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= 103 | github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= 104 | github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 105 | github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 106 | github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= 107 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 108 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 109 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 110 | github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= 111 | github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= 112 | github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= 113 | github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= 114 | github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= 115 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 116 | github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= 117 | github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= 118 | github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= 119 | github.com/jsimonetti/rtnetlink v0.0.0-20200319143528-d89fb9e42094 h1:FPWTRjBELlivjc2Nv0I8EbRFyXXQ0p/sVtaH191yqvA= 120 | github.com/jsimonetti/rtnetlink v0.0.0-20200319143528-d89fb9e42094/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= 121 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 122 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 123 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 124 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 125 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 126 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 127 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 128 | github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 129 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 130 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 131 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 132 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 133 | github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 134 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 135 | github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 136 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 137 | github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= 138 | github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= 139 | github.com/mdlayher/netlink v1.1.0 h1:mpdLgm+brq10nI9zM1BpX1kpDbh3NLl3RSnVq6ZSkfg= 140 | github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= 141 | github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= 142 | github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= 143 | github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 144 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 145 | github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 146 | github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= 147 | github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= 148 | github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 149 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 150 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 151 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 152 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 153 | github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= 154 | github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= 155 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 156 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 157 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 158 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 159 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 160 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 161 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 162 | github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= 163 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 164 | github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= 165 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 166 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 167 | github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 168 | github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 169 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 170 | github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 171 | github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= 172 | github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= 173 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 174 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 175 | github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= 176 | github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= 177 | github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 h1:udFKJ0aHUL60LboW/A+DfgoHVedieIzIXE8uylPue0U= 178 | github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= 179 | github.com/shuLhan/go-bindata v4.0.0+incompatible h1:xD8LkuVZLV5OOn/IEuFdt6EEAW7deWiqgwaaSGhjAJc= 180 | github.com/shuLhan/go-bindata v4.0.0+incompatible/go.mod h1:pkcPAATLBDD2+SpAPnX5vEM90F7fcwHCvvLCMXcmw3g= 181 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 182 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 183 | github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= 184 | github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= 185 | github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 186 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= 187 | github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= 188 | github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= 189 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 190 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 191 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 192 | github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= 193 | github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= 194 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 195 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 196 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 197 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 198 | github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= 199 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 200 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 201 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 202 | github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= 203 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 204 | github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= 205 | github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= 206 | github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= 207 | github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= 208 | github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k= 209 | github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= 210 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= 211 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 212 | go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= 213 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 214 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 215 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 216 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 217 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 218 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 219 | golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 220 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 221 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 222 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 223 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 224 | golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= 225 | golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= 226 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 227 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 228 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 229 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 230 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 231 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 232 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 233 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 234 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 235 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 236 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 237 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 238 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 239 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 240 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 241 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 242 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 243 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 244 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 245 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 246 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 247 | golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 248 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 249 | golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 250 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 251 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 252 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 253 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 254 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 255 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 256 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 257 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 258 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 259 | golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 260 | golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 261 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 262 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 263 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 264 | golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= 265 | golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= 266 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 267 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 268 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 269 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 270 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 271 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 272 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 273 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 274 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 275 | golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 276 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 277 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 278 | golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 279 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 280 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 281 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 282 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 283 | golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 284 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 285 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 286 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 287 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 288 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 289 | golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 290 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 291 | golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 292 | golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 293 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 294 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 295 | golang.org/x/sys v0.0.0-20200320181252-af34d8274f85/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 296 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 297 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 298 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 299 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 300 | golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= 301 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 302 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 303 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 304 | golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 305 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 306 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 307 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 308 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 309 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 310 | golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 311 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 312 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 313 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 314 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 315 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 316 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 317 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 318 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 319 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 320 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 321 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 322 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 323 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 324 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 325 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 326 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 327 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 328 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 329 | golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 330 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 331 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 332 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 333 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 334 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 335 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 336 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 337 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 338 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 339 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 340 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 341 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 342 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 343 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 344 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 345 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 346 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 347 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 348 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 349 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 350 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 351 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 352 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 353 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 354 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 355 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 356 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 357 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 358 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 359 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 360 | gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 361 | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= 362 | gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 363 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 364 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 365 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 366 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 367 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 368 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 369 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 370 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 371 | -------------------------------------------------------------------------------- /pkg/assets/probe.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-bindata. DO NOT EDIT. 2 | // sources: 3 | // ebpf/bin/probe.o 4 | 5 | package assets 6 | 7 | 8 | import ( 9 | "bytes" 10 | "compress/gzip" 11 | "fmt" 12 | "io" 13 | "io/ioutil" 14 | "os" 15 | "path/filepath" 16 | "strings" 17 | "time" 18 | ) 19 | 20 | func bindataRead(data []byte, name string) ([]byte, error) { 21 | gz, err := gzip.NewReader(bytes.NewBuffer(data)) 22 | if err != nil { 23 | return nil, fmt.Errorf("Read %q: %v", name, err) 24 | } 25 | 26 | var buf bytes.Buffer 27 | _, err = io.Copy(&buf, gz) 28 | clErr := gz.Close() 29 | 30 | if err != nil { 31 | return nil, fmt.Errorf("Read %q: %v", name, err) 32 | } 33 | if clErr != nil { 34 | return nil, err 35 | } 36 | 37 | return buf.Bytes(), nil 38 | } 39 | 40 | 41 | type asset struct { 42 | bytes []byte 43 | info fileInfoEx 44 | } 45 | 46 | type fileInfoEx interface { 47 | os.FileInfo 48 | MD5Checksum() string 49 | } 50 | 51 | type bindataFileInfo struct { 52 | name string 53 | size int64 54 | mode os.FileMode 55 | modTime time.Time 56 | md5checksum string 57 | } 58 | 59 | func (fi bindataFileInfo) Name() string { 60 | return fi.name 61 | } 62 | func (fi bindataFileInfo) Size() int64 { 63 | return fi.size 64 | } 65 | func (fi bindataFileInfo) Mode() os.FileMode { 66 | return fi.mode 67 | } 68 | func (fi bindataFileInfo) ModTime() time.Time { 69 | return fi.modTime 70 | } 71 | func (fi bindataFileInfo) MD5Checksum() string { 72 | return fi.md5checksum 73 | } 74 | func (fi bindataFileInfo) IsDir() bool { 75 | return false 76 | } 77 | func (fi bindataFileInfo) Sys() interface{} { 78 | return nil 79 | } 80 | 81 | var _bindataProbeO = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x7b\x7f\x6c\x5b\xd7\x75\xff\x7d\xa4\x28\xd2\x92\x62\xd3\xb2\xa4\xb0\x4e\xd2\xaf\x1c\xe7\x9b\x32\x6c\x6c\xf3\xa7\x2c\xb7\x4d\xa7\x06\x4d\xaa\x25\x59\xaa\x6d\xf9\xa1\xac\x48\x9f\x68\x9a\x96\x14\xdb\x12\x43\x32\x36\x29\x17\x9b\xb7\x2c\xa8\x52\x24\xa9\x96\x38\xad\xda\x26\xb3\x9c\x04\xa9\xfe\x29\xaa\xa0\x69\xac\x02\x5d\x25\x0c\xe8\xaa\x6d\xc8\x20\x60\x6d\x67\x60\x6b\xe1\x01\x6b\x20\x60\xe9\xa6\xa1\xd9\x2a\x74\x81\x39\xbc\x7b\x3f\x87\x7c\xef\xbc\xf7\x24\x3a\x0d\xd3\xae\xe3\xfb\x43\x87\xf7\x73\xcf\x3d\x9f\x73\xcf\xbd\xef\xbc\xc3\xcb\xa7\x3f\xba\xed\xae\xdb\x3d\x9a\x26\xe8\xd2\xc4\xcf\x45\xad\x55\xbb\xd6\x32\xb5\xcf\x03\xf8\x7b\x93\xd0\xc4\x85\x56\x85\x65\x1e\x7a\xbb\x62\xc8\xa5\x17\x54\xdb\xef\x11\xe2\xed\x4a\xa5\x12\x62\xc6\x1e\x93\x1c\x42\x2c\xf9\x55\xbb\xdb\xbf\xa3\x8a\x6f\x17\x42\x9c\x6e\x5b\x57\x76\x5e\x86\x9d\x56\x21\xd6\x1d\xec\x2c\x1d\x86\x2c\x28\x79\xa1\xa5\x66\xdf\x23\x84\x70\xd3\xaf\xf2\xc3\xef\xa5\x11\x25\x9f\x35\xf9\xa7\xfc\xd8\xb0\xcd\x67\x63\x93\xf9\xd0\xf8\xa5\x1e\xab\x9d\x53\x42\x88\x5e\x23\x3e\x6d\x57\x16\x9f\x7b\x85\x72\x90\xf7\xdf\xab\x79\x95\xff\x69\xcc\xdb\x23\x44\xa5\x52\xa9\x18\xe3\x3e\x64\xb4\x85\x75\x3e\xee\xfe\xa8\xf9\xa5\xd3\x1d\xb2\x3f\xb3\xfb\x6d\xb4\x95\x7e\x56\xf3\x0b\xa3\xa7\x5b\x0b\xa8\x75\xd2\x34\xe1\x13\x42\xf8\xa4\x15\xbb\x5f\xc6\x3a\x05\x64\xbf\x0f\xfa\xff\x5d\xb9\x4a\xfa\x1b\x90\x23\x9c\xf4\x5b\x1c\xe2\xbb\x84\x7d\xc6\xd7\xd3\x6d\x3e\xb4\xef\xf8\xbc\xea\x5d\xb7\x25\xe0\x14\xb7\x6e\xdc\x0b\xe9\xe0\xe6\x71\x7c\xaf\x79\x6b\xeb\xd2\x25\xda\xa4\xbc\x46\x46\xda\xaf\xa9\xf5\x37\xf6\x81\x11\xb2\x7d\x9d\xca\x8e\x4f\xbc\xa4\xc6\x8d\x86\xad\x7e\x4f\xfd\x72\x7e\x5f\x00\xde\x8d\x2c\x91\x46\x3b\xd3\xd3\x02\xde\x67\xe1\x67\x48\x04\xa5\xbc\x59\xf2\x76\x6b\x77\x8a\x76\xcc\xb3\x43\xea\xcd\x60\x5e\x61\x36\xfe\x49\x8c\x4f\xc9\xfd\xd4\xad\x7d\x42\xde\x09\xc6\x38\xb5\xbf\x1e\xc7\xbc\x6e\x6e\xd0\xbc\x0e\xc2\x8f\x5d\x2a\xfe\x9d\xb5\xf1\xff\x6a\xc4\xd9\xab\xf6\xe3\xbe\xbd\xdf\xaf\xa8\x75\xbb\x5b\xec\x84\x7f\x5d\x72\xdc\x23\x0d\xf6\x6f\xaf\x25\xee\x3e\xb1\x07\xfb\xe7\x0e\xb1\x03\x7e\x04\x25\x7e\xa4\xc1\xeb\xdf\x09\xfe\x7f\x43\x1c\xee\x17\xdb\xc0\xdf\x26\xf1\x7b\x1a\xcc\xef\x01\xff\x8f\x2b\xd6\x7d\x14\x00\xfe\x71\xf0\x47\xdf\x5d\x7e\x3c\xb7\xb6\xba\x0f\xd2\x63\x8c\xf7\x73\xbf\x1c\x6f\xb7\xb8\x09\xf3\xfa\x40\x63\xe6\x55\x9d\xcf\x3f\x54\x14\xcf\x37\x2a\x0d\x59\xbf\xba\xe3\x17\x7e\x97\xe3\x07\x1e\xf0\x67\x4e\xaa\x7d\x42\x79\xb6\x71\xfb\xf4\x6b\x88\xe7\xe3\x6a\xbc\x5a\xbe\x6a\x5e\x27\xbd\xd3\xbb\x95\xfd\xd3\xbb\xd7\x21\xd7\x20\x2f\x41\x5e\x84\x5c\x85\x5c\x81\x5c\x86\x5c\x84\x5c\x80\x9c\x87\x9c\x83\x9c\x85\x9c\xa9\x90\x9f\x3e\x59\xe7\xa8\x76\xfa\x61\xc4\x05\x7a\x4b\xe7\x31\x4f\x4d\xd5\x5f\xc6\xf3\x25\x88\x71\x41\xa9\xaf\xd6\xa9\x5b\xeb\x56\xf3\xc9\xd7\xe2\xd2\xe2\xf0\xbc\xaf\xad\xc3\x0e\xac\x77\x97\x94\xa3\x9a\x8a\x6f\xda\xa3\x1e\x7c\x9f\xdc\x43\xf1\x50\xf3\x48\x6b\x1d\x4c\x2f\xc0\xf4\xe6\x2b\xe6\xfd\x93\xf6\x28\xbf\x46\x3d\x4a\xff\x93\xc8\xdf\xa7\x23\x73\x98\x27\xd5\x33\x8a\xdf\xef\x57\x75\x8b\xad\x5e\xcc\x73\xbf\x55\xdd\x53\xd6\xa2\xc2\xbc\x3e\x65\x2d\x2c\xcc\xeb\x54\xd6\x7a\x85\x79\xbd\xca\x5a\x48\x98\xd7\xad\xac\x05\x85\x79\xfd\xca\xa8\xaf\x68\x1d\xcb\xd5\xfd\xb0\x58\x5d\x27\x43\x63\xe9\x25\xc4\xb7\x45\x88\x19\xa3\x4e\x42\x3d\x10\xf2\x30\xbf\xbd\x4a\x5e\xf0\x09\x91\xc3\xf8\xf7\x6d\x52\xc7\xd0\xfa\x9b\xf7\xf5\x4c\x5d\x75\xfb\x37\x54\x3c\xd2\x43\x52\x66\xae\x56\xeb\xb4\x54\x82\x9d\x80\xda\x07\xb4\x4f\x8c\xba\xd5\x1c\xff\x7b\x35\xaa\x53\x76\x5b\xfc\xa9\xdd\x6f\xb4\x2f\xa9\x3e\x3d\x6b\xd9\xa7\x59\xad\x0d\xf5\x69\x3b\xd6\x93\xea\x53\x15\x5f\xfa\x5e\xe0\xf7\x22\x7e\x5b\xcc\xcf\x27\xfc\xb0\xb3\x81\xba\xd5\x2f\xfd\xd9\x6a\xdc\xd2\xa3\x88\x37\xab\x57\x6b\x7e\xd6\x5b\xaf\xdd\xa2\xe2\x53\x66\x79\xe8\xcb\x67\x59\x1e\xba\xb2\xf5\x72\xcd\xb3\x21\x9a\xf7\x7e\xf8\x49\xf5\xda\x14\xea\xb5\x2f\xb1\x7a\xed\x26\xac\x1f\x9e\xb3\x57\x53\xbd\x76\x23\xc6\x3f\x8a\x7a\xed\x2c\xab\xd7\xae\xc7\xbc\x6e\x6e\xd0\xbc\xba\xe1\x47\xbd\xf5\xda\x57\x58\xbd\xb6\xbd\xc1\xfe\xb1\xb8\x5f\xad\xf6\xff\xff\xfe\xbc\xaf\xf2\xa7\xed\x7e\xf8\x13\x6b\x1c\x9a\xf9\xfe\x57\x93\xef\xf9\x39\x40\xb7\xf6\xdb\xec\xfb\xc1\xd7\x55\x7c\x1a\x96\x6f\x5e\x40\xdd\x33\x87\xfb\xee\x1e\xf6\xfd\xe0\x5c\x83\xf9\x9f\x06\x3f\xed\x73\xc5\xe3\x13\x9f\x07\x6f\xb4\x41\xbc\xfc\x7e\x47\x3d\xdb\x30\xbe\x47\x30\xcf\x42\x83\xe7\x35\x06\x9e\xa3\x0d\x5e\x37\xb7\xf8\x35\x8a\xef\x77\x30\xaf\x3b\x1b\x3c\xaf\x01\xf0\x7c\x54\x8d\x47\x1d\x56\x1e\xcd\xa9\x7e\xbf\x4a\x70\xe6\xba\x25\xcc\xf2\xf1\x86\xa9\x6e\x30\xec\xb7\x30\xfd\x61\x97\xfc\x1d\x30\xe9\x1b\xf9\x6f\x84\xe9\xbd\x69\xb2\x4b\xf6\x48\xff\xd7\xed\x1c\x73\xb3\x78\xe5\xae\x30\x5e\x63\xff\x07\xe2\xd5\xac\xf3\xad\xf3\x6b\xd6\xf9\xcd\x3a\xff\x3d\x89\x7b\xb3\xce\x6f\xd6\xf9\xcd\x3a\xbf\x59\xe7\x37\xeb\xfc\x2b\x8c\xdf\x6f\x66\x9d\xdf\xac\xc3\xac\xf3\x6b\xd6\x61\xcd\x3a\xec\x3d\x89\x7b\xb3\x0e\x6b\xd6\x61\xcd\x3a\xac\x59\x87\x35\xeb\xb0\x2b\x8c\xdf\x6f\x66\x1d\x46\xfd\xf4\xbe\xe3\x95\xbe\xaf\x7a\xaf\x9f\xea\x87\x1e\x8b\xdf\xd5\xf7\x56\xe7\x61\x2f\xe0\xf2\xde\x2a\xf2\x75\xdd\xef\xad\xda\xf2\xbb\x72\xa4\x9c\x56\xe7\xa0\x19\xbc\x2f\x58\xce\x8c\x29\x5e\x81\x73\x63\xd8\x31\x9e\x27\x39\xd3\xf9\x24\xcf\x53\xe5\x9e\x9c\x25\x2e\x6e\xcf\x45\x7a\x2f\xd3\xa8\xef\x8c\x1d\xbf\xf4\x55\xb4\xfd\x42\x5c\x32\xf2\xe5\xc3\x35\x3e\xcb\x79\xab\x69\xdc\x3c\x7b\xde\xad\xb1\xe7\x5d\x0b\xde\x0b\x0d\x31\xbd\x7f\x31\x9f\xb7\x66\x6a\xf1\x70\x7a\xcf\x84\x9e\x2b\x6e\xf1\x7d\xec\x1d\xbe\xdf\x4b\xef\x9b\xa5\xcf\xab\x78\x64\x82\xca\xb0\x6b\x3c\xb1\x5f\x4e\x4f\xad\xdb\xe2\xd7\x5b\xc7\xb9\xf3\xe9\x29\xc4\x7f\x0a\x75\xc9\x14\xea\x92\x29\xd4\x25\x53\xa8\x4b\xa6\x50\x97\x4c\xa9\xe7\x59\xf9\x45\xc5\x67\xf0\xf0\x38\x2e\x3a\x9d\x87\x9b\xfc\x6a\x61\xfa\xdf\x76\xd0\xa7\xf7\x7c\xcd\x7a\xcb\x9b\xac\x8f\xd9\x9f\x05\x36\xee\x92\xc3\xfa\xbf\xf3\xf5\x41\xdd\x73\x7e\x11\xeb\xa3\x9e\xfb\x54\x0f\x94\x3d\xa8\x13\x22\xd6\xba\x8e\xd7\x13\x66\xbe\x45\xa7\xfb\x77\xaf\xf3\xbe\xda\xfa\xfc\xfd\x9d\xbd\xef\x57\x4e\xab\xfb\x9a\xea\x6c\xaa\xbb\xbe\x07\x69\xd4\xdb\x67\x84\x10\x27\xf6\xaa\xef\x65\x46\xbd\x72\xa6\x52\xa9\x90\xbd\x1d\xa8\xe3\xa8\xbe\x3b\x05\x69\xc4\xdd\xe0\x99\x84\x5d\x8a\x43\xb5\xee\x0b\xaa\xb6\x4f\xa8\xb8\x19\x3c\x03\x8c\x67\xf9\x1d\xf1\x84\x18\x4f\x08\x3c\xed\x96\xf1\x34\x5f\xf3\x3c\x85\xe4\x57\xbf\x8f\xb8\xdb\x67\x75\x6e\x50\xb5\x6d\xeb\xa3\xbe\xbe\x88\x74\x0c\xdf\x0f\x50\xe7\x1d\x8b\xa8\xe7\x42\x26\x82\xef\x09\x11\xe4\xc3\x08\xee\xc7\x08\xee\xc7\x08\xee\x47\xda\x4f\x11\xdc\x8f\x11\xdc\x8f\x11\x7c\x4f\x88\xe0\x7b\x42\x04\xdf\x13\x50\x27\x9f\x8e\xe0\x7b\x42\x64\x06\x72\x1a\xf2\x0c\x64\x09\x32\x07\x39\x06\x39\x02\x39\x0c\x39\x04\x39\x08\x39\x00\xd9\x0f\x19\x85\x0c\x43\xf6\x42\x86\x20\x83\x90\x01\x48\x01\xb9\x71\x19\xf3\x87\x5c\x83\xbc\x04\x79\x11\x72\x15\x72\x05\x72\x19\x72\x11\x72\x01\x72\x1e\x72\x4e\xca\xfb\xe5\xf7\x72\x21\x76\x60\x1d\xcc\xff\xef\x31\x77\xb9\x56\x7f\x1b\xeb\xf2\x69\x4d\xdd\x17\xfb\xea\xf8\xbf\x8e\x6e\xd1\x55\x6d\xfb\x65\xfd\xf0\xdc\x65\x6e\xff\xb9\xcb\x9b\xfc\x3f\x89\xcb\xff\x1f\xd8\xcf\x4b\x66\x95\x5d\xd3\xfd\x3c\xeb\x64\xd7\xc5\xde\x56\xf9\xe2\x4a\x7f\x37\xec\x16\xea\x7b\x5c\x3a\xad\xbe\x57\x67\xf0\x3d\xb7\x5a\xd7\xed\x7e\xcb\x31\xff\x2c\xbd\x88\xb6\x57\x88\xb7\x1c\xec\x6f\xe5\x37\xf9\x4b\xf5\x06\xdd\x97\x54\x5f\x8d\x22\x5e\x14\xb7\x07\xb5\xab\xc4\x95\xcd\x4b\x3d\x48\x6b\xf3\xa8\x3f\x8f\x7a\x1d\xfc\x35\xbe\x13\x19\xfb\x49\x4e\xab\x45\x34\x2f\xd3\xb5\x0d\x21\x69\xc6\xc6\x7e\x35\x63\xe3\x7e\x51\x6c\xe4\x93\x3c\xf8\xab\xf6\xe6\xd7\xeb\xa2\xd8\xf4\x8b\x66\x6c\xf8\xb5\x0d\x67\x6f\xf2\x76\x6a\xc6\xc6\x72\x35\x63\xe3\x7e\xb5\x98\x73\x71\xf3\xb2\x5c\xb4\x6f\x66\x45\x73\xdf\xf0\xcb\x83\x3d\x33\x8b\xda\xb2\x79\xd5\xae\x4f\x0c\xdd\x25\x2e\x57\x2a\x15\xda\x32\xda\xd4\xef\x89\xc0\x67\xda\xe5\xaf\x43\x21\x7a\xb6\xe3\x5a\x35\x7d\xbe\x56\x08\x91\x34\x61\x03\xcc\xae\xd1\x7f\x8f\xa9\x1d\xd5\xec\xfd\x45\x63\xab\x02\x9f\x71\x18\x7f\x76\x8b\xf1\xaf\x0a\x21\xe6\x34\xbb\x6f\xd4\xff\x7d\x21\x44\x0e\xdf\xef\x4b\x0e\xfd\x6f\x09\x21\xd6\x36\xe9\xef\xd2\x84\x18\xc1\xf9\xc3\xaa\xcf\xde\x9f\xd4\x84\x88\x6e\x53\xed\x33\x1e\x87\xf9\x9b\x7c\x9e\xde\xe6\x30\x7f\x4d\x88\x85\x76\xf7\xfe\xb3\x5b\x8c\x7f\xd5\xd4\xcf\xbf\x07\xc9\xf9\x9b\xb0\x21\x87\xfe\xb7\x4c\x58\xc0\xc1\xff\x2e\x13\x36\xe7\x30\x3e\x69\xea\x9f\x71\x9a\xbf\x09\x5b\x14\xf6\xfe\xa2\xa9\x7f\x41\xd4\x77\xfd\xb3\x3c\xaf\xfc\x8f\x0a\xc7\xdf\x90\xc7\x43\x1e\xb1\xcc\xf0\x67\xe4\x31\x4f\x40\xac\x31\xdc\x0f\x7c\x98\xcd\xeb\xb4\x5f\xe1\x63\x0c\x7f\xd9\x07\x7d\x36\xcf\xaf\xb5\x28\xbc\xd4\x6a\xc5\x73\xb0\xcf\x7f\x47\x1c\x6c\x55\xf8\x06\xdb\x4f\x77\xc0\xfe\x25\xa6\x1f\x81\x7d\x1e\xff\x7f\x82\x9f\x7c\xdd\x46\x80\x97\x18\xbe\x0f\xbc\xbd\x6c\x1f\x1d\x00\x6f\x90\xf9\xff\x34\x78\x67\x18\xfe\x03\xe8\xcf\x5a\x61\x71\x1b\xe6\xbb\xc1\xf4\xbf\x05\x7f\x06\x98\x3f\xb7\x00\x1f\x0c\x58\xf1\x36\xf8\xb9\xc0\xf0\x0e\xf0\x06\xfc\x56\x7c\x12\x7e\xe6\x18\x7e\x3d\xfc\xb9\xc4\xf0\xdd\xe0\x0d\x79\xad\xf8\x17\xc1\x5b\x62\xf8\xbf\x83\xf7\x0c\xc3\x1f\x05\x3e\xcd\xf0\x7b\xe0\xcf\x3a\x2b\x52\xbe\x00\xde\x39\xb6\xee\x15\xf0\xae\x31\xfc\x07\xb0\xd3\xcb\xd6\x3d\x00\x9c\xe7\xc3\xcf\xc9\xf9\x7a\xc4\x6c\x87\x15\xbf\xec\x57\x78\xe0\x2a\x2b\x9e\x07\x1e\x62\xf8\xf3\x3e\xe8\x6f\xb7\xe2\x2f\xb5\x28\x3c\xdc\x69\xc5\x47\xc1\xbb\xc2\xec\xfc\x16\xee\xc7\xf9\x9d\x56\xfc\x63\xb0\x3f\xc3\xec\xef\x81\xfd\x21\x66\xe7\xef\xe1\xe7\x22\xc3\xef\x07\x1e\x66\x76\x6e\x00\xef\x6a\x97\x15\xbf\x11\xbc\xcb\xcc\x9f\xc7\xc1\x3b\xc0\xe6\xf5\x3a\xf4\x07\x59\x3c\x3f\x82\xf9\xce\x33\xfd\x05\xf8\xb3\xce\xfc\x4c\x02\xdf\xd8\x65\xc5\x35\xf8\x39\xc2\xfc\xf4\x82\x77\x91\xd9\x3f\x0a\x3f\x7b\x99\x9d\xf7\xc1\x9f\x19\x86\xef\x04\xef\x0a\x8b\xcf\x53\xe0\x0d\xef\xb0\xe2\x6f\x80\x37\xca\xf0\x29\xe0\xfd\x0c\xbf\x13\xfe\xcc\xb1\x5a\xf3\x49\xf0\x0e\xb1\x38\xff\x17\x78\x67\x19\xfe\x3a\xec\xac\xb2\x38\x0b\xe0\x97\x18\xfe\xc7\x72\xbe\x6d\xb6\x7c\xfe\x9f\x7e\x85\xf3\x7c\x3e\x0e\x9c\xe7\xf3\xb3\x3e\xe8\xb3\xbc\xf4\x95\x16\x85\xf3\x7c\xfe\x69\xf0\xf2\x7c\xde\xd7\xaa\x70\x9e\xcf\xfb\x61\x9f\xe7\xf3\x10\xec\xf3\x7c\xfe\x37\xf0\x93\xe7\xf3\xbb\x81\xf3\x7c\x7e\x0d\x78\x79\x3e\xbf\x0e\xbc\x3c\x9f\x9f\x01\x2f\xcf\xe7\xdf\x85\x3e\xcf\xe7\x09\xcc\x97\xe7\xf3\xaf\xc2\x1f\x9e\xcf\x3f\x08\x9c\xe7\xf3\x0d\xd8\xe7\xf9\xfc\x17\xf0\x87\xe7\xf3\x07\x81\xf3\x7c\x1e\x84\x3f\x3c\x9f\x07\xc0\xcb\xf3\xf9\x63\x88\x0f\xcf\xe7\x3f\x82\x3f\x3c\x9f\x3f\x0c\x9c\xe7\xf3\x5b\xe1\x0f\xcf\xe7\x7f\x0a\x5e\x9e\xcf\x7f\x0a\x5e\x9e\xcf\xbf\x0b\x3b\x3c\x9f\x6f\x78\x15\xce\xf3\xf9\x8f\xa5\x9d\x0e\xf9\xbf\x5d\xe6\xeb\x35\x9f\xc2\x03\x4c\xff\x87\x52\x7f\xbb\x18\x60\xf8\xdf\x49\x3c\x28\x36\x18\x3e\x29\xf1\x4e\x5b\xdd\x7c\xd8\xa7\xf0\x7e\xa6\xff\x5a\x8b\xc2\x67\xf8\xef\x1c\xd2\x4e\x97\xad\xfe\x5d\x90\x78\x8f\x98\x67\xf6\x47\x24\x1e\x12\x73\x0c\xff\x8e\xe4\x6d\xb1\xc5\xe7\x0f\x91\x37\x38\xef\xd7\xa5\x7e\xab\x4d\xff\x14\xf4\xf9\x7d\xfa\x10\xf2\x58\x98\xe1\x3f\x43\x9e\xe1\xf1\xf9\x0e\x3d\x17\x98\xfe\x87\x81\x8f\x31\xfc\x7b\xe0\xe5\xf7\xfb\x22\xf0\x61\xb6\xaf\xca\xc8\xdb\x03\x6c\x5f\xfd\x14\xf9\x73\x98\xe1\xbf\x0b\x3b\x25\x86\xff\x3e\xe6\x75\x89\xe1\x09\xf8\x19\x62\xfb\xf0\x3e\xf0\x96\x18\xfe\x13\xf0\x4e\x33\x7c\x1e\xbc\x7c\x9f\x3f\x41\x75\x02\xcb\x0f\x3f\xa2\xe7\x14\xc3\x83\xc0\xa7\x19\x3e\x46\xf6\x59\x7c\xee\xa6\xe7\x1a\xd3\xff\x4b\xf8\xb9\xcc\xf2\xc9\xed\xc0\xe7\x98\xfe\x2e\xd8\x0f\xb2\xbc\xd1\x0d\xff\x4b\x0c\x2f\xd1\x73\x87\xe1\x1f\x84\x3f\x43\x8c\xf7\x1c\x78\x79\x7e\xdb\x4b\x75\x0b\xc3\xe7\xe0\xcf\x0a\xc3\x3f\x45\xf1\x64\xeb\xf8\x26\xad\x23\xc3\x1f\x80\x9d\x85\x36\x2b\xfe\x13\xe8\x8f\xb4\x0b\xdb\xe5\x15\x1e\x3b\x28\x71\xe7\x13\x35\xaf\x68\x75\xc1\x03\x2e\x78\x9b\x0b\xce\x1f\xee\x84\x6f\x77\xc1\x9d\x0f\xb0\xbc\xa2\xd3\x05\xef\x72\xc1\x7b\x5c\xf0\x90\x0d\xab\x78\x84\xd8\x29\x6e\xa8\xb6\x29\x22\x3b\x34\x03\xff\xff\x36\xfc\x9b\x46\x8d\x85\x77\xea\x8d\xeb\x5a\xe4\x8f\xbf\x95\xf8\x35\x36\x3c\x24\xf1\xeb\x6d\xf8\x75\xd2\xfe\x5e\x1b\x3e\x2b\xf5\xaf\xb3\xe1\x2f\x4b\xfc\xfd\x36\xfc\x09\x89\xef\xb1\xe1\x1f\xf0\x1a\x59\xdb\x63\x3b\x07\x19\x04\xce\xcf\x3f\xda\x85\xc2\xf9\xb9\xce\x9b\x1e\x03\xaf\xed\x13\x7a\x5e\x3d\x21\xf1\x56\x1b\x1e\xf3\x28\x3b\xfc\x7c\x67\x9f\x66\xe0\xb5\x75\xa4\x3a\xe8\x0d\x89\xd7\xf6\x09\x9d\x67\xfc\xa3\xf4\xa7\xb6\x4f\xe8\x1c\xe3\x15\xa9\x5f\xdb\x27\x54\x37\xfd\x50\xf2\xd6\xf6\x27\x9d\x9b\x9c\x94\x78\x9b\x0d\x7f\x3f\xfc\xe4\xe7\x30\xf7\x21\x3e\xfc\xfc\xa7\xd3\xe3\x7c\xbc\xaa\x21\x6e\x74\x51\xfc\x3e\x0b\x3b\xfc\x9c\x6a\x3f\xf4\xf9\xf9\xd1\x35\x5e\x63\x1d\xaf\xad\xda\xa1\x75\x3c\x24\xf1\xff\x67\xc3\x4f\x49\xbc\xd7\x86\x3f\x23\x79\x6b\xf7\x05\x9d\xcf\x1c\x92\xbc\xb5\xfd\x4f\xe7\x2e\x19\x19\xcf\xda\xfd\x42\xe7\x35\xbd\xa6\xf9\x9d\x13\xea\x7f\xa7\xa9\xfd\xe7\x74\xde\x6c\x6a\xaf\xb3\x36\xd5\x23\x1a\xee\x99\x11\x53\xfb\x15\xa3\xfe\x31\xb5\x2f\x08\x51\x7d\x3e\x1b\xed\xd7\x8c\xe7\x0f\x6b\xf7\x7a\xad\xfa\x17\xbd\xd6\xfe\x85\x16\x6b\xff\x90\x8f\xe9\xb3\xf6\x70\x2b\xeb\x6f\xb5\xda\x1b\xf2\x5b\xfb\x17\x58\x3b\x14\xb0\xea\xcf\x04\xac\xfd\x62\x1b\xd3\x6f\xab\xb5\x8d\x1a\x68\xc5\xd4\x3e\x6f\xec\x83\xf6\x5a\xfb\x05\xc3\x9f\x76\x6b\x3c\x17\x3b\xac\xf6\xd6\x3b\xac\xfc\xd3\x57\x59\xdb\x23\xdb\x99\x3f\x3b\x58\x3b\x68\xf5\x67\x31\x68\xf5\x27\xb7\xd3\xea\xcf\xc6\x4e\xeb\xf8\x52\x27\xf3\xa7\x93\xf1\xef\xb2\xf6\xaf\xb0\x76\xb4\xcb\xaa\x3f\xd7\x65\xed\x0f\x74\x5b\xdb\xab\xc2\xba\x9f\xcc\xfb\xed\x95\x3a\xfa\xc3\xc2\x1a\xcf\x00\xdb\x7f\xe6\xfd\x6a\xf8\x73\x91\xb5\x17\x3c\x6c\x7f\xb1\xfd\x38\xd4\x62\x8d\x67\xc0\x67\x8d\xe7\xb2\xcf\x1a\xcf\x41\xb6\xff\x56\x58\x7b\xc0\xcf\xf8\x37\xd9\x7f\x46\xfb\x0c\xdb\x8f\xeb\xac\x7f\x98\xed\xc7\x66\x3c\xdc\xe3\x71\xce\xf4\x5c\xa4\xf8\xcc\xb3\xf6\xb2\xb0\xce\x2f\xa8\x59\xfb\x47\x58\x7b\x55\xb3\xce\x9f\xc7\x7f\xd1\xd4\xff\x9c\xc0\x8f\x57\x68\x3f\x6f\xf8\x6b\x6a\x7f\x93\x8d\x37\xda\xd3\xac\x3d\xb8\x49\xff\xf3\x38\x87\xa7\xf6\x53\xf4\xbe\x82\xa9\x3d\x6c\x6a\x7f\x9e\xc5\xe3\x29\x96\xff\x67\x4c\xcf\x0d\xea\xbf\xc8\xda\x1b\xac\x1d\xd2\x18\x3f\x6b\x0f\x9b\xda\x7f\x66\xf0\xb3\xfe\x59\x53\xfb\x69\x16\xbf\x67\xd8\x7e\x3d\xcb\x9e\x37\xcf\x9a\xfe\xcf\xc7\x68\x7f\xc1\xe0\x37\xb5\xbf\xc8\xe2\x6d\xcc\xb5\x64\x6a\x7f\xc9\xf8\x90\xcf\x16\xb2\x45\x3d\x53\x2c\x89\x51\xc8\x13\xe9\x5c\xe1\xc0\xe1\xdc\x51\x3d\x33\x39\x51\xcc\x96\x8a\x62\x7f\x3e\x7b\x7c\xbf\xfc\x54\xc8\x4e\x1c\xd1\xb3\x27\xb3\x13\x45\x51\xcc\xa7\x33\xd9\xdc\xe4\xf8\x44\x51\xd7\x0b\x99\xb1\xec\x11\x12\xb9\xfc\x64\x26\x5b\x28\xe8\xd9\xd2\xb8\x1a\x5a\xd3\x3c\x20\x35\x0e\x38\xe8\x49\x4e\x69\xb8\x50\xe3\x37\x3e\xd4\x5a\xb9\xfc\xe4\x28\x9a\xe9\xe3\xc7\x27\x4f\x65\x8f\xe8\x87\xc7\x27\xd2\xf9\xf1\x2c\x43\x33\x93\x93\xc7\x0c\xf0\x58\x2e\x3f\x79\x38\xab\x17\xb2\x99\x47\xf2\xe3\xc5\xb2\x0e\x93\xd2\x27\xd5\x77\xc0\xd6\xa7\x9f\xcc\xe6\x0b\xe3\x93\x13\xb6\x20\xe8\xa3\xd9\x09\xb2\x98\x19\xcb\x66\x8e\xe9\x63\xd9\xe3\xb9\x6c\x5e\xcf\xa4\x8f\x1f\x37\x9b\xb4\x77\x6e\x19\xa9\xa3\x93\xf9\x63\xf5\x44\x4a\xea\x39\xcd\x2a\x97\x1f\x75\x9d\x95\x11\x36\xa7\x41\x6e\x03\x44\x2e\x3f\x59\xcc\x66\x8a\xf2\xf3\xb1\x7c\xb6\xa8\x86\xea\x85\x72\x41\x41\xac\x2d\xcd\x90\xda\x01\x5d\x2f\xf5\x25\xad\x7d\x4e\x1d\x26\xbb\x66\xd4\x0e\x71\xeb\xe3\xe9\x44\xdc\xd9\xbc\xa5\xc7\x64\xdf\x8c\xda\x21\xfd\xf8\x78\x26\x3b\x51\xc8\xaa\x3d\x9e\x1d\xd3\x8f\xe6\xd3\x27\xb2\x6a\xf5\x8b\xa3\xe3\xb4\x99\xc4\xd1\x6c\x31\x33\x66\xec\x10\x7d\xfc\x88\xa9\xf7\xe8\x11\xc2\x94\x82\x11\x6c\xa3\x95\x9b\xcc\x3d\x72\x3c\x5d\xcc\xa2\x57\x4f\x4f\x1c\xa9\xf6\x59\x46\x13\x58\x48\x9f\xcc\xea\x93\x87\x1f\xd2\x8f\x1e\xa9\xe7\xce\xca\x66\xea\xbb\xb3\xb2\x19\x71\x22\x3d\x3e\xb1\x3f\x23\xf6\x17\x8a\xf9\x62\xfa\xb0\xd8\x5f\x28\x9f\x30\xe4\x5d\xb7\xde\x1a\x8b\xeb\x87\xa4\x8c\x41\x46\x95\xec\xd7\xe3\x87\xd0\x1f\x27\x85\x38\x69\xc4\xa1\x12\x93\x32\xa5\xf7\x43\x33\xd5\x0f\x4d\x7c\x88\xd2\x87\xb8\x9e\xa4\xae\x24\x75\xa9\x0f\xfd\x7a\x82\x54\x12\xa4\x92\x20\x95\x6a\x57\x8c\xba\x62\xd4\x85\x0f\x7d\xfa\x41\xe5\xc2\x41\x68\x1e\x84\xe2\x41\xe8\x1d\xc4\x64\xa4\x3c\xa4\xf7\xa9\x66\x9f\x1a\xd4\x47\xce\xf5\x91\x73\x7d\xe4\x1c\x14\x13\xa4\x92\x20\x95\x04\xa9\x54\xbb\xe2\xd4\x15\xa7\xae\x38\x46\xc7\x20\x53\xf0\x35\xa5\x68\x53\x14\xae\x14\x85\x2b\x45\xe1\x4a\xc1\x5d\x52\x89\x91\x4a\x8c\x54\xd4\x87\xa4\x9e\x94\xed\x84\x92\x71\x34\x49\xc6\x20\xa3\x55\x3c\x45\x1d\x29\xea\x49\x55\x87\x54\xc7\x54\x07\x25\x31\x7b\x52\x49\x90\x4a\x82\x54\xaa\x5d\x71\xea\x8a\x53\x57\x1c\xa3\x63\x49\x15\xf3\x84\xc4\x21\xfb\xd1\xec\x53\x32\xa5\x44\x02\x68\x5c\x4f\x25\xc8\xcf\x04\xf9\x89\x71\x49\xc8\xb8\xea\xe8\xd7\xe3\x86\x3c\xa8\x44\x0c\xb2\x0f\xcd\x14\x64\x12\x32\xa1\x64\x14\xcd\xb8\xde\x17\x07\x0f\x3e\x44\xe9\x43\x5c\x4f\x51\x57\x8a\xba\xd4\x87\x7e\x3d\x49\x2a\x49\x52\x49\x92\x4a\x12\x2a\x09\x52\x49\x90\x4a\x82\x54\xaa\x5d\x31\xea\x8a\x51\x57\xac\xea\x56\x8c\xdc\x8a\x91\x5b\x31\x70\xc7\x88\x9b\x54\x92\xa4\x92\x84\x4a\x82\x54\x12\xa4\x92\x20\x95\x04\x54\xe2\x90\x31\x52\x8d\x91\x6a\x8c\x54\xab\x5d\xa9\x28\xc5\x21\x4a\x71\x88\xc2\x97\x28\xf9\x42\x2a\x49\x52\x49\x42\x25\x01\x19\x27\xd5\x38\xa9\xc6\x49\x35\x0e\x95\x18\xa9\xc4\x48\x25\x46\x2a\xb1\xa8\x78\x37\xae\x35\xaf\x7a\x9f\x9e\x5f\x83\x9f\x52\xf2\x39\x76\x14\xa8\x31\xbd\x30\x30\x7e\x92\x48\xe7\x4a\xfd\xdd\x56\x9c\x9f\x2c\xde\x50\xfb\x0a\x6d\xb5\x8b\x97\x8b\xe8\x5c\x23\x8c\x52\x99\xc6\xd3\x19\xcd\xb2\xc7\x99\xbf\x04\x5e\xfe\xbb\x0b\xe7\xff\xb6\xc7\x99\x7f\xf1\x3e\x25\xe9\x7c\x24\x8c\xb3\x41\xce\x9f\x76\xe1\x9f\xef\xa9\x8f\xff\x41\x17\xfe\x8b\x0e\xfc\xad\x0e\xfc\x2f\xba\xf0\x5f\xbc\x5a\x49\xfe\x5e\x11\xe7\x3f\xe7\xc2\xbf\x01\x7e\xfa\xbe\x13\xc6\x58\xce\x7f\x9b\x0b\xff\xc8\x9e\xfa\xf8\x3f\xe6\xc2\x1f\x18\xb6\xf3\xb7\x39\xf0\x5f\xd6\x9c\xf9\xd7\x22\x4a\xf2\xf7\xa6\x38\xff\x2f\x34\x67\xfe\xd0\x03\x4a\xd2\x5d\x16\x96\xbf\xca\xd9\xf9\x7f\xee\xb2\xff\x85\xfa\x77\x1d\xdb\x7b\x59\x9c\xff\x67\x2e\xfb\x7f\x10\xfc\xe6\xf5\xdf\xee\xc0\xff\xba\xcb\xfc\x87\xf6\x81\xcf\xb3\x39\xff\x5f\xbb\xcc\x7f\xcc\x81\x3f\xe8\xc0\x7f\x87\x0b\xff\xf0\x01\x25\xf9\xef\xe0\x9c\xff\x76\x17\xfe\xe9\x07\xac\x3c\x61\x79\xae\x69\xe7\xff\x0b\xaf\x33\xff\x06\x16\x8e\xbf\xb7\xc6\xf9\xbf\xe5\x75\xe6\x9f\x75\x58\xff\x2e\x07\xfe\x27\x5d\xe6\x3f\x9d\x50\x92\xbf\x17\xc7\xf9\x1f\x77\x99\xff\x8a\x43\xfc\x7b\x1c\xf8\x33\x6e\xf9\x37\xa9\x24\x7f\xef\x8e\xf3\xeb\x2e\xfb\x6f\xcd\x81\x3f\xe4\xc0\xbf\x00\x7e\xfe\x0c\x59\x07\xff\xb5\x6c\xfd\xf9\x2f\x51\x7f\xe5\x32\xbe\xa3\xaf\xbe\xf1\x3d\x5e\xe7\xf1\xe1\x83\xf5\x8d\x7f\xc6\x85\xff\xe3\xfd\xf5\x8d\x3f\xef\x32\x7e\xe4\x50\x7d\xe3\x93\x2e\xfe\x7f\xe6\x43\xf5\x8d\xcf\xbb\x8c\x9f\xfd\x70\x7d\xe3\x3f\xeb\xe2\xff\xab\x1f\xa9\x6f\xfc\x2e\x97\xf1\xab\xb7\xd4\x37\x3e\xa4\x39\x8f\x7f\xf3\xa3\xf5\x8d\x17\x2e\xf3\x0f\x0c\x38\xeb\xf3\xfa\x25\xe8\xc2\xdf\xe1\x32\x9e\xb7\x3b\xc0\xcf\x7f\x79\x0d\x62\xfc\x56\xf9\x27\xe0\x92\x7f\x02\x7f\xa0\xe4\x80\xe9\xf9\x77\xa3\xc3\xfd\xb7\xee\xb5\x73\x1b\xd7\xdc\xad\x4a\x4e\x9b\xce\xf3\xbf\x6c\x1a\x4f\xbf\x10\xfd\x4f\x00\x00\x00\xff\xff\x2b\xf5\xc4\x01\x28\x6e\x00\x00") 82 | 83 | func bindataProbeOBytes() ([]byte, error) { 84 | return bindataRead( 85 | _bindataProbeO, 86 | "/probe.o", 87 | ) 88 | } 89 | 90 | 91 | 92 | func bindataProbeO() (*asset, error) { 93 | bytes, err := bindataProbeOBytes() 94 | if err != nil { 95 | return nil, err 96 | } 97 | 98 | info := bindataFileInfo{ 99 | name: "/probe.o", 100 | size: 28200, 101 | md5checksum: "", 102 | mode: os.FileMode(420), 103 | modTime: time.Unix(1627997999, 0), 104 | } 105 | 106 | a := &asset{bytes: bytes, info: info} 107 | 108 | return a, nil 109 | } 110 | 111 | 112 | // 113 | // Asset loads and returns the asset for the given name. 114 | // It returns an error if the asset could not be found or 115 | // could not be loaded. 116 | // 117 | func Asset(name string) ([]byte, error) { 118 | cannonicalName := strings.Replace(name, "\\", "/", -1) 119 | if f, ok := _bindata[cannonicalName]; ok { 120 | a, err := f() 121 | if err != nil { 122 | return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) 123 | } 124 | return a.bytes, nil 125 | } 126 | return nil, &os.PathError{Op: "open", Path: name, Err: os.ErrNotExist} 127 | } 128 | 129 | // 130 | // MustAsset is like Asset but panics when Asset would return an error. 131 | // It simplifies safe initialization of global variables. 132 | // nolint: deadcode 133 | // 134 | func MustAsset(name string) []byte { 135 | a, err := Asset(name) 136 | if err != nil { 137 | panic("asset: Asset(" + name + "): " + err.Error()) 138 | } 139 | 140 | return a 141 | } 142 | 143 | // 144 | // AssetInfo loads and returns the asset info for the given name. 145 | // It returns an error if the asset could not be found or could not be loaded. 146 | // 147 | func AssetInfo(name string) (os.FileInfo, error) { 148 | cannonicalName := strings.Replace(name, "\\", "/", -1) 149 | if f, ok := _bindata[cannonicalName]; ok { 150 | a, err := f() 151 | if err != nil { 152 | return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) 153 | } 154 | return a.info, nil 155 | } 156 | return nil, &os.PathError{Op: "open", Path: name, Err: os.ErrNotExist} 157 | } 158 | 159 | // 160 | // AssetNames returns the names of the assets. 161 | // nolint: deadcode 162 | // 163 | func AssetNames() []string { 164 | names := make([]string, 0, len(_bindata)) 165 | for name := range _bindata { 166 | names = append(names, name) 167 | } 168 | return names 169 | } 170 | 171 | // 172 | // _bindata is a table, holding each asset generator, mapped to its name. 173 | // 174 | var _bindata = map[string]func() (*asset, error){ 175 | "/probe.o": bindataProbeO, 176 | } 177 | 178 | // 179 | // AssetDir returns the file names below a certain 180 | // directory embedded in the file by go-bindata. 181 | // For example if you run go-bindata on data/... and data contains the 182 | // following hierarchy: 183 | // data/ 184 | // foo.txt 185 | // img/ 186 | // a.png 187 | // b.png 188 | // then AssetDir("data") would return []string{"foo.txt", "img"} 189 | // AssetDir("data/img") would return []string{"a.png", "b.png"} 190 | // AssetDir("foo.txt") and AssetDir("notexist") would return an error 191 | // AssetDir("") will return []string{"data"}. 192 | // 193 | func AssetDir(name string) ([]string, error) { 194 | node := _bintree 195 | if len(name) != 0 { 196 | cannonicalName := strings.Replace(name, "\\", "/", -1) 197 | pathList := strings.Split(cannonicalName, "/") 198 | for _, p := range pathList { 199 | node = node.Children[p] 200 | if node == nil { 201 | return nil, &os.PathError{ 202 | Op: "open", 203 | Path: name, 204 | Err: os.ErrNotExist, 205 | } 206 | } 207 | } 208 | } 209 | if node.Func != nil { 210 | return nil, &os.PathError{ 211 | Op: "open", 212 | Path: name, 213 | Err: os.ErrNotExist, 214 | } 215 | } 216 | rv := make([]string, 0, len(node.Children)) 217 | for childName := range node.Children { 218 | rv = append(rv, childName) 219 | } 220 | return rv, nil 221 | } 222 | 223 | 224 | type bintree struct { 225 | Func func() (*asset, error) 226 | Children map[string]*bintree 227 | } 228 | 229 | var _bintree = &bintree{Func: nil, Children: map[string]*bintree{ 230 | "": {Func: nil, Children: map[string]*bintree{ 231 | "probe.o": {Func: bindataProbeO, Children: map[string]*bintree{}}, 232 | }}, 233 | }} 234 | 235 | // RestoreAsset restores an asset under the given directory 236 | func RestoreAsset(dir, name string) error { 237 | data, err := Asset(name) 238 | if err != nil { 239 | return err 240 | } 241 | info, err := AssetInfo(name) 242 | if err != nil { 243 | return err 244 | } 245 | err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) 246 | if err != nil { 247 | return err 248 | } 249 | err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) 250 | if err != nil { 251 | return err 252 | } 253 | return os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) 254 | } 255 | 256 | // RestoreAssets restores an asset under the given directory recursively 257 | func RestoreAssets(dir, name string) error { 258 | children, err := AssetDir(name) 259 | // File 260 | if err != nil { 261 | return RestoreAsset(dir, name) 262 | } 263 | // Dir 264 | for _, child := range children { 265 | err = RestoreAssets(dir, filepath.Join(name, child)) 266 | if err != nil { 267 | return err 268 | } 269 | } 270 | return nil 271 | } 272 | 273 | func _filePath(dir, name string) string { 274 | cannonicalName := strings.Replace(name, "\\", "/", -1) 275 | return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) 276 | } 277 | -------------------------------------------------------------------------------- /pkg/model/byteorder.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 GUILLAUME FOURNIER 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package model 18 | 19 | import ( 20 | "encoding/binary" 21 | "unsafe" 22 | ) 23 | 24 | // GetHostByteOrder guesses the hosts byte order 25 | func GetHostByteOrder() binary.ByteOrder { 26 | var i int32 = 0x01020304 27 | u := unsafe.Pointer(&i) 28 | pb := (*byte)(u) 29 | b := *pb 30 | if b == 0x04 { 31 | return binary.LittleEndian 32 | } 33 | 34 | return binary.BigEndian 35 | } 36 | 37 | // ByteOrder holds the hosts byte order 38 | var ByteOrder binary.ByteOrder 39 | 40 | func init() { 41 | ByteOrder = GetHostByteOrder() 42 | } 43 | -------------------------------------------------------------------------------- /pkg/model/const.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 GUILLAUME FOURNIER 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package model 18 | 19 | import "fmt" 20 | 21 | type BPFCmd uint32 22 | 23 | const ( 24 | BpfMapCreate BPFCmd = iota 25 | BpfCmdMapLookupElem 26 | BpfCmdMapUpdateElem 27 | BpfCmdMapDeleteElem 28 | BpfCmdMapGetNextKey 29 | BpfProgLoad 30 | BpfObjPin 31 | BpfObjGet 32 | BpfProgAttach 33 | BpfProgDetach 34 | BpfProgTestRun 35 | BpfProgGetNextId 36 | BpfMapGetNextId 37 | BpfProgGetFdById 38 | BpfMapGetFdById 39 | BpfObjGetInfoByFd 40 | BpfProgQuery 41 | BpfRawTracepointOpen 42 | BpfBtfLoad 43 | BpfBtfGetFdById 44 | BpfTaskFdQuery 45 | BpfMapLookupAndDeleteElem 46 | BpfMapFreeze 47 | BpfBtfGetNextId 48 | BpfMapLookupBatch 49 | BpfMapLookupAndDeleteBatch 50 | BpfMapUpdateBatch 51 | BpfMapDeleteBatch 52 | BpfLinkCreate 53 | BpfLinkUpdate 54 | BpfLinkGetFdById 55 | BpfLinkGetNextId 56 | BpfEnableStats 57 | BpfIterCreate 58 | BpfLinkDetach 59 | BpfProgBindMap 60 | ) 61 | 62 | func (cmd BPFCmd) MarshalJSON() ([]byte, error) { 63 | return []byte(`"` + cmd.String() + `"`), nil 64 | } 65 | 66 | func (cmd BPFCmd) String() string { 67 | switch cmd { 68 | case BpfMapCreate: 69 | return "BpfMapCreate" 70 | case BpfCmdMapLookupElem: 71 | return "BpfMapLookupElem" 72 | case BpfCmdMapUpdateElem: 73 | return "BpfMapUpdateElem" 74 | case BpfCmdMapDeleteElem: 75 | return "BpfMapDeleteElem" 76 | case BpfCmdMapGetNextKey: 77 | return "BpfMapGetNextKey" 78 | case BpfProgLoad: 79 | return "BpfProgLoad" 80 | case BpfObjPin: 81 | return "BpfObjPin" 82 | case BpfObjGet: 83 | return "BpfObjGet" 84 | case BpfProgAttach: 85 | return "BpfProgAttach" 86 | case BpfProgDetach: 87 | return "BpfProgDetach" 88 | case BpfProgTestRun: 89 | return "BpfProgTestRun" 90 | case BpfProgGetNextId: 91 | return "BpfProgGetNextId" 92 | case BpfMapGetNextId: 93 | return "BpfMapGetNextId" 94 | case BpfProgGetFdById: 95 | return "BpfProgGetFdById" 96 | case BpfMapGetFdById: 97 | return "BpfMapGetFdById" 98 | case BpfObjGetInfoByFd: 99 | return "BpfObjGetInfoByFd" 100 | case BpfProgQuery: 101 | return "BpfProgQuery" 102 | case BpfRawTracepointOpen: 103 | return "BpfRawTracepointOpen" 104 | case BpfBtfLoad: 105 | return "BpfBtfLoad" 106 | case BpfBtfGetFdById: 107 | return "BpfBtfGetFdById" 108 | case BpfTaskFdQuery: 109 | return "BpfTaskFdQuery" 110 | case BpfMapLookupAndDeleteElem: 111 | return "BpfMapLookupAndDeleteElem" 112 | case BpfMapFreeze: 113 | return "BpfMapFreeze" 114 | case BpfBtfGetNextId: 115 | return "BpfBtfGetNextId" 116 | case BpfMapLookupBatch: 117 | return "BpfMapLookupBatch" 118 | case BpfMapLookupAndDeleteBatch: 119 | return "BpfMapLookupAndDeleteBatch" 120 | case BpfMapUpdateBatch: 121 | return "BpfMapUpdateBatch" 122 | case BpfMapDeleteBatch: 123 | return "BpfMapDeleteBatch" 124 | case BpfLinkCreate: 125 | return "BpfLinkCreate" 126 | case BpfLinkUpdate: 127 | return "BpfLinkUpdate" 128 | case BpfLinkGetFdById: 129 | return "BpfLinkGetFdById" 130 | case BpfLinkGetNextId: 131 | return "BpfLinkGetNextId" 132 | case BpfEnableStats: 133 | return "BpfEnableStats" 134 | case BpfIterCreate: 135 | return "BpfIterCreate" 136 | case BpfLinkDetach: 137 | return "BpfLinkDetach" 138 | case BpfProgBindMap: 139 | return "BpfProgBindMap" 140 | } 141 | return fmt.Sprintf("BPFCmd(%d)", cmd) 142 | } 143 | 144 | type HelperFunc uint32 145 | 146 | const ( 147 | BpfUnspec HelperFunc = iota 148 | BpfMapLookupElem 149 | BpfMapUpdateElem 150 | BpfMapDeleteElem 151 | BpfProbeRead 152 | BpfKtimeGetNs 153 | BpfTracePrintk 154 | BpfGetPrandomU32 155 | BpfGetSmpProcessorId 156 | BpfSkbStoreBytes 157 | BpfL3CsumReplace 158 | BpfL4CsumReplace 159 | BpfTailCall 160 | BpfCloneRedirect 161 | BpfGetCurrentPidTgid 162 | BpfGetCurrentUidGid 163 | BpfGetCurrentComm 164 | BpfGetCgroupClassid 165 | BpfSkbVlanPush 166 | BpfSkbVlanPop 167 | BpfSkbGetTunnelKey 168 | BpfSkbSetTunnelKey 169 | BpfPerfEventRead 170 | BpfRedirect 171 | BpfGetRouteRealm 172 | BpfPerfEventOutput 173 | BpfSkbLoadBytes 174 | BpfGetStackid 175 | BpfCsumDiff 176 | BpfSkbGetTunnelOpt 177 | BpfSkbSetTunnelOpt 178 | BpfSkbChangeProto 179 | BpfSkbChangeType 180 | BpfSkbUnderCgroup 181 | BpfGetHashRecalc 182 | BpfGetCurrentTask 183 | BpfProbeWriteUser 184 | BpfCurrentTaskUnderCgroup 185 | BpfSkbChangeTail 186 | BpfSkbPullData 187 | BpfCsumUpdate 188 | BpfSetHashInvalid 189 | BpfGetNumaNodeId 190 | BpfSkbChangeHead 191 | BpfXdpAdjustHead 192 | BpfProbeReadStr 193 | BpfGetSocketCookie 194 | BpfGetSocketUid 195 | BpfSetHash 196 | BpfSetsockopt 197 | BpfSkbAdjustRoom 198 | BpfRedirectMap 199 | BpfSkRedirectMap 200 | BpfSockMapUpdate 201 | BpfXdpAdjustMeta 202 | BpfPerfEventReadValue 203 | BpfPerfProgReadValue 204 | BpfGetsockopt 205 | BpfOverrideReturn 206 | BpfSockOpsCbFlagsSet 207 | BpfMsgRedirectMap 208 | BpfMsgApplyBytes 209 | BpfMsgCorkBytes 210 | BpfMsgPullData 211 | BpfBind 212 | BpfXdpAdjustTail 213 | BpfSkbGetXfrmState 214 | BpfGetStack 215 | BpfSkbLoadBytesRelative 216 | BpfFibLookup 217 | BpfSockHashUpdate 218 | BpfMsgRedirectHash 219 | BpfSkRedirectHash 220 | BpfLwtPushEncap 221 | BpfLwtSeg6StoreBytes 222 | BpfLwtSeg6AdjustSrh 223 | BpfLwtSeg6Action 224 | BpfRcRepeat 225 | BpfRcKeydown 226 | BpfSkbCgroupId 227 | BpfGetCurrentCgroupId 228 | BpfGetLocalStorage 229 | BpfSkSelectReuseport 230 | BpfSkbAncestorCgroupId 231 | BpfSkLookupTcp 232 | BpfSkLookupUdp 233 | BpfSkRelease 234 | BpfMapPushElem 235 | BpfMapPopElem 236 | BpfMapPeekElem 237 | BpfMsgPushData 238 | BpfMsgPopData 239 | BpfRcPointerRel 240 | BpfSpinLock 241 | BpfSpinUnlock 242 | BpfSkFullsock 243 | BpfTcpSock 244 | BpfSkbEcnSetCe 245 | BpfGetListenerSock 246 | BpfSkcLookupTcp 247 | BpfTcpCheckSyncookie 248 | BpfSysctlGetName 249 | BpfSysctlGetCurrentValue 250 | BpfSysctlGetNewValue 251 | BpfSysctlSetNewValue 252 | BpfStrtol 253 | BpfStrtoul 254 | BpfSkStorageGet 255 | BpfSkStorageDelete 256 | BpfSendSignal 257 | BpfTcpGenSyncookie 258 | BpfSkbOutput 259 | BpfProbeReadUser 260 | BpfProbeReadKernel 261 | BpfProbeReadUserStr 262 | BpfProbeReadKernelStr 263 | BpfTcpSendAck 264 | BpfSendSignalThread 265 | BpfJiffies64 266 | BpfReadBranchRecords 267 | BpfGetNsCurrentPidTgid 268 | BpfXdpOutput 269 | BpfGetNetnsCookie 270 | BpfGetCurrentAncestorCgroupId 271 | BpfSkAssign 272 | BpfKtimeGetBootNs 273 | BpfSeqPrintf 274 | BpfSeqWrite 275 | BpfSkCgroupId 276 | BpfSkAncestorCgroupId 277 | BpfRingbufOutput 278 | BpfRingbufReserve 279 | BpfRingbufSubmit 280 | BpfRingbufDiscard 281 | BpfRingbufQuery 282 | BpfCsumLevel 283 | BpfSkcToTcp6Sock 284 | BpfSkcToTcpSock 285 | BpfSkcToTcpTimewaitSock 286 | BpfSkcToTcpRequestSock 287 | BpfSkcToUdp6Sock 288 | BpfGetTaskStack 289 | BpfLoadHdrOpt 290 | BpfStoreHdrOpt 291 | BpfReserveHdrOpt 292 | BpfInodeStorageGet 293 | BpfInodeStorageDelete 294 | BpfDPath 295 | BpfCopyFromUser 296 | BpfSnprintfBtf 297 | BpfSeqPrintfBtf 298 | BpfSkbCgroupClassid 299 | BpfRedirectNeigh 300 | BpfPerCpuPtr 301 | BpfThisCpuPtr 302 | BpfRedirectPeer 303 | BpfTaskStorageGet 304 | BpfTaskStorageDelete 305 | BpfGetCurrentTaskBtf 306 | BpfBprmOptsSet 307 | BpfKtimeGetCoarseNs 308 | BpfImaInodeHash 309 | BpfSockFromFile 310 | BpfCheckMtu 311 | BpfForEachMapElem 312 | BpfSnprintf 313 | ) 314 | 315 | func (f HelperFunc) MarshalJSON() ([]byte, error) { 316 | return []byte(`"` + f.String() + `"`), nil 317 | } 318 | 319 | func (f HelperFunc) String() string { 320 | switch f { 321 | case BpfUnspec: 322 | return "BpfUnspec" 323 | case BpfMapLookupElem: 324 | return "BpfMapLookupElem" 325 | case BpfMapUpdateElem: 326 | return "BpfMapUpdateElem" 327 | case BpfMapDeleteElem: 328 | return "BpfMapDeleteElem" 329 | case BpfProbeRead: 330 | return "BpfProbeRead" 331 | case BpfKtimeGetNs: 332 | return "BpfKtimeGetNs" 333 | case BpfTracePrintk: 334 | return "BpfTracePrintk" 335 | case BpfGetPrandomU32: 336 | return "BpfGetPrandomU32" 337 | case BpfGetSmpProcessorId: 338 | return "BpfGetSmpProcessorId" 339 | case BpfSkbStoreBytes: 340 | return "BpfSkbStoreBytes" 341 | case BpfL3CsumReplace: 342 | return "BpfL3CsumReplace" 343 | case BpfL4CsumReplace: 344 | return "BpfL4CsumReplace" 345 | case BpfTailCall: 346 | return "BpfTailCall" 347 | case BpfCloneRedirect: 348 | return "BpfCloneRedirect" 349 | case BpfGetCurrentPidTgid: 350 | return "BpfGetCurrentPidTgid" 351 | case BpfGetCurrentUidGid: 352 | return "BpfGetCurrentUidGid" 353 | case BpfGetCurrentComm: 354 | return "BpfGetCurrentComm" 355 | case BpfGetCgroupClassid: 356 | return "BpfGetCgroupClassid" 357 | case BpfSkbVlanPush: 358 | return "BpfSkbVlanPush" 359 | case BpfSkbVlanPop: 360 | return "BpfSkbVlanPop" 361 | case BpfSkbGetTunnelKey: 362 | return "BpfSkbGetTunnelKey" 363 | case BpfSkbSetTunnelKey: 364 | return "BpfSkbSetTunnelKey" 365 | case BpfPerfEventRead: 366 | return "BpfPerfEventRead" 367 | case BpfRedirect: 368 | return "BpfRedirect" 369 | case BpfGetRouteRealm: 370 | return "BpfGetRouteRealm" 371 | case BpfPerfEventOutput: 372 | return "BpfPerfEventOutput" 373 | case BpfSkbLoadBytes: 374 | return "BpfSkbLoadBytes" 375 | case BpfGetStackid: 376 | return "BpfGetStackid" 377 | case BpfCsumDiff: 378 | return "BpfCsumDiff" 379 | case BpfSkbGetTunnelOpt: 380 | return "BpfSkbGetTunnelOpt" 381 | case BpfSkbSetTunnelOpt: 382 | return "BpfSkbSetTunnelOpt" 383 | case BpfSkbChangeProto: 384 | return "BpfSkbChangeProto" 385 | case BpfSkbChangeType: 386 | return "BpfSkbChangeType" 387 | case BpfSkbUnderCgroup: 388 | return "BpfSkbUnderCgroup" 389 | case BpfGetHashRecalc: 390 | return "BpfGetHashRecalc" 391 | case BpfGetCurrentTask: 392 | return "BpfGetCurrentTask" 393 | case BpfProbeWriteUser: 394 | return "BpfProbeWriteUser" 395 | case BpfCurrentTaskUnderCgroup: 396 | return "BpfCurrentTaskUnderCgroup" 397 | case BpfSkbChangeTail: 398 | return "BpfSkbChangeTail" 399 | case BpfSkbPullData: 400 | return "BpfSkbPullData" 401 | case BpfCsumUpdate: 402 | return "BpfCsumUpdate" 403 | case BpfSetHashInvalid: 404 | return "BpfSetHashInvalid" 405 | case BpfGetNumaNodeId: 406 | return "BpfGetNumaNodeId" 407 | case BpfSkbChangeHead: 408 | return "BpfSkbChangeHead" 409 | case BpfXdpAdjustHead: 410 | return "BpfXdpAdjustHead" 411 | case BpfProbeReadStr: 412 | return "BpfProbeReadStr" 413 | case BpfGetSocketCookie: 414 | return "BpfGetSocketCookie" 415 | case BpfGetSocketUid: 416 | return "BpfGetSocketUid" 417 | case BpfSetHash: 418 | return "BpfSetHash" 419 | case BpfSetsockopt: 420 | return "BpfSetsockopt" 421 | case BpfSkbAdjustRoom: 422 | return "BpfSkbAdjustRoom" 423 | case BpfRedirectMap: 424 | return "BpfRedirectMap" 425 | case BpfSkRedirectMap: 426 | return "BpfSkRedirectMap" 427 | case BpfSockMapUpdate: 428 | return "BpfSockMapUpdate" 429 | case BpfXdpAdjustMeta: 430 | return "BpfXdpAdjustMeta" 431 | case BpfPerfEventReadValue: 432 | return "BpfPerfEventReadValue" 433 | case BpfPerfProgReadValue: 434 | return "BpfPerfProgReadValue" 435 | case BpfGetsockopt: 436 | return "BpfGetsockopt" 437 | case BpfOverrideReturn: 438 | return "BpfOverrideReturn" 439 | case BpfSockOpsCbFlagsSet: 440 | return "BpfSockOpsCbFlagsSet" 441 | case BpfMsgRedirectMap: 442 | return "BpfMsgRedirectMap" 443 | case BpfMsgApplyBytes: 444 | return "BpfMsgApplyBytes" 445 | case BpfMsgCorkBytes: 446 | return "BpfMsgCorkBytes" 447 | case BpfMsgPullData: 448 | return "BpfMsgPullData" 449 | case BpfBind: 450 | return "BpfBind" 451 | case BpfXdpAdjustTail: 452 | return "BpfXdpAdjustTail" 453 | case BpfSkbGetXfrmState: 454 | return "BpfSkbGetXfrmState" 455 | case BpfGetStack: 456 | return "BpfGetStack" 457 | case BpfSkbLoadBytesRelative: 458 | return "BpfSkbLoadBytesRelative" 459 | case BpfFibLookup: 460 | return "BpfFibLookup" 461 | case BpfSockHashUpdate: 462 | return "BpfSockHashUpdate" 463 | case BpfMsgRedirectHash: 464 | return "BpfMsgRedirectHash" 465 | case BpfSkRedirectHash: 466 | return "BpfSkRedirectHash" 467 | case BpfLwtPushEncap: 468 | return "BpfLwtPushEncap" 469 | case BpfLwtSeg6StoreBytes: 470 | return "BpfLwtSeg6StoreBytes" 471 | case BpfLwtSeg6AdjustSrh: 472 | return "BpfLwtSeg6AdjustSrh" 473 | case BpfLwtSeg6Action: 474 | return "BpfLwtSeg6Action" 475 | case BpfRcRepeat: 476 | return "BpfRcRepeat" 477 | case BpfRcKeydown: 478 | return "BpfRcKeydown" 479 | case BpfSkbCgroupId: 480 | return "BpfSkbCgroupId" 481 | case BpfGetCurrentCgroupId: 482 | return "BpfGetCurrentCgroupId" 483 | case BpfGetLocalStorage: 484 | return "BpfGetLocalStorage" 485 | case BpfSkSelectReuseport: 486 | return "BpfSkSelectReuseport" 487 | case BpfSkbAncestorCgroupId: 488 | return "BpfSkbAncestorCgroupId" 489 | case BpfSkLookupTcp: 490 | return "BpfSkLookupTcp" 491 | case BpfSkLookupUdp: 492 | return "BpfSkLookupUdp" 493 | case BpfSkRelease: 494 | return "BpfSkRelease" 495 | case BpfMapPushElem: 496 | return "BpfMapPushElem" 497 | case BpfMapPopElem: 498 | return "BpfMapPopElem" 499 | case BpfMapPeekElem: 500 | return "BpfMapPeekElem" 501 | case BpfMsgPushData: 502 | return "BpfMsgPushData" 503 | case BpfMsgPopData: 504 | return "BpfMsgPopData" 505 | case BpfRcPointerRel: 506 | return "BpfRcPointerRel" 507 | case BpfSpinLock: 508 | return "BpfSpinLock" 509 | case BpfSpinUnlock: 510 | return "BpfSpinUnlock" 511 | case BpfSkFullsock: 512 | return "BpfSkFullsock" 513 | case BpfTcpSock: 514 | return "BpfTcpSock" 515 | case BpfSkbEcnSetCe: 516 | return "BpfSkbEcnSetCe" 517 | case BpfGetListenerSock: 518 | return "BpfGetListenerSock" 519 | case BpfSkcLookupTcp: 520 | return "BpfSkcLookupTcp" 521 | case BpfTcpCheckSyncookie: 522 | return "BpfTcpCheckSyncookie" 523 | case BpfSysctlGetName: 524 | return "BpfSysctlGetName" 525 | case BpfSysctlGetCurrentValue: 526 | return "BpfSysctlGetCurrentValue" 527 | case BpfSysctlGetNewValue: 528 | return "BpfSysctlGetNewValue" 529 | case BpfSysctlSetNewValue: 530 | return "BpfSysctlSetNewValue" 531 | case BpfStrtol: 532 | return "BpfStrtol" 533 | case BpfStrtoul: 534 | return "BpfStrtoul" 535 | case BpfSkStorageGet: 536 | return "BpfSkStorageGet" 537 | case BpfSkStorageDelete: 538 | return "BpfSkStorageDelete" 539 | case BpfSendSignal: 540 | return "BpfSendSignal" 541 | case BpfTcpGenSyncookie: 542 | return "BpfTcpGenSyncookie" 543 | case BpfSkbOutput: 544 | return "BpfSkbOutput" 545 | case BpfProbeReadUser: 546 | return "BpfProbeReadUser" 547 | case BpfProbeReadKernel: 548 | return "BpfProbeReadKernel" 549 | case BpfProbeReadUserStr: 550 | return "BpfProbeReadUserStr" 551 | case BpfProbeReadKernelStr: 552 | return "BpfProbeReadKernelStr" 553 | case BpfTcpSendAck: 554 | return "BpfTcpSendAck" 555 | case BpfSendSignalThread: 556 | return "BpfSendSignalThread" 557 | case BpfJiffies64: 558 | return "BpfJiffies64" 559 | case BpfReadBranchRecords: 560 | return "BpfReadBranchRecords" 561 | case BpfGetNsCurrentPidTgid: 562 | return "BpfGetNsCurrentPidTgid" 563 | case BpfXdpOutput: 564 | return "BpfXdpOutput" 565 | case BpfGetNetnsCookie: 566 | return "BpfGetNetnsCookie" 567 | case BpfGetCurrentAncestorCgroupId: 568 | return "BpfGetCurrentAncestorCgroupId" 569 | case BpfSkAssign: 570 | return "BpfSkAssign" 571 | case BpfKtimeGetBootNs: 572 | return "BpfKtimeGetBootNs" 573 | case BpfSeqPrintf: 574 | return "BpfSeqPrintf" 575 | case BpfSeqWrite: 576 | return "BpfSeqWrite" 577 | case BpfSkCgroupId: 578 | return "BpfSkCgroupId" 579 | case BpfSkAncestorCgroupId: 580 | return "BpfSkAncestorCgroupId" 581 | case BpfRingbufOutput: 582 | return "BpfRingbufOutput" 583 | case BpfRingbufReserve: 584 | return "BpfRingbufReserve" 585 | case BpfRingbufSubmit: 586 | return "BpfRingbufSubmit" 587 | case BpfRingbufDiscard: 588 | return "BpfRingbufDiscard" 589 | case BpfRingbufQuery: 590 | return "BpfRingbufQuery" 591 | case BpfCsumLevel: 592 | return "BpfCsumLevel" 593 | case BpfSkcToTcp6Sock: 594 | return "BpfSkcToTcp6Sock" 595 | case BpfSkcToTcpSock: 596 | return "BpfSkcToTcpSock" 597 | case BpfSkcToTcpTimewaitSock: 598 | return "BpfSkcToTcpTimewaitSock" 599 | case BpfSkcToTcpRequestSock: 600 | return "BpfSkcToTcpRequestSock" 601 | case BpfSkcToUdp6Sock: 602 | return "BpfSkcToUdp6Sock" 603 | case BpfGetTaskStack: 604 | return "BpfGetTaskStack" 605 | case BpfLoadHdrOpt: 606 | return "BpfLoadHdrOpt" 607 | case BpfStoreHdrOpt: 608 | return "BpfStoreHdrOpt" 609 | case BpfReserveHdrOpt: 610 | return "BpfReserveHdrOpt" 611 | case BpfInodeStorageGet: 612 | return "BpfInodeStorageGet" 613 | case BpfInodeStorageDelete: 614 | return "BpfInodeStorageDelete" 615 | case BpfDPath: 616 | return "BpfDPath" 617 | case BpfCopyFromUser: 618 | return "BpfCopyFromUser" 619 | case BpfSnprintfBtf: 620 | return "BpfSnprintfBtf" 621 | case BpfSeqPrintfBtf: 622 | return "BpfSeqPrintfBtf" 623 | case BpfSkbCgroupClassid: 624 | return "BpfSkbCgroupClassid" 625 | case BpfRedirectNeigh: 626 | return "BpfRedirectNeigh" 627 | case BpfPerCpuPtr: 628 | return "BpfPerCpuPtr" 629 | case BpfThisCpuPtr: 630 | return "BpfThisCpuPtr" 631 | case BpfRedirectPeer: 632 | return "BpfRedirectPeer" 633 | case BpfTaskStorageGet: 634 | return "BpfTaskStorageGet" 635 | case BpfTaskStorageDelete: 636 | return "BpfTaskStorageDelete" 637 | case BpfGetCurrentTaskBtf: 638 | return "BpfGetCurrentTaskBtf" 639 | case BpfBprmOptsSet: 640 | return "BpfBprmOptsSet" 641 | case BpfKtimeGetCoarseNs: 642 | return "BpfKtimeGetCoarseNs" 643 | case BpfImaInodeHash: 644 | return "BpfImaInodeHash" 645 | case BpfSockFromFile: 646 | return "BpfSockFromFile" 647 | case BpfCheckMtu: 648 | return "BpfCheckMtu" 649 | case BpfForEachMapElem: 650 | return "BpfForEachMapElem" 651 | case BpfSnprintf: 652 | return "BpfSnprintf" 653 | } 654 | return fmt.Sprintf("HelperFunc(%d)", f) 655 | } 656 | 657 | type MapType uint32 658 | 659 | const ( 660 | BpfMapTypeUnspec MapType = iota 661 | BpfMapTypeHash 662 | BpfMapTypeArray 663 | BpfMapTypeProgArray 664 | BpfMapTypePerfEventArray 665 | BpfMapTypePercpuHash 666 | BpfMapTypePercpuArray 667 | BpfMapTypeStackTrace 668 | BpfMapTypeCgroupArray 669 | BpfMapTypeLruHash 670 | BpfMapTypeLruPercpuHash 671 | BpfMapTypeLpmTrie 672 | BpfMapTypeArrayOfMaps 673 | BpfMapTypeHashOfMaps 674 | BpfMapTypeDevmap 675 | BpfMapTypeSockmap 676 | BpfMapTypeCpumap 677 | BpfMapTypeXskmap 678 | BpfMapTypeSockhash 679 | BpfMapTypeCgroupStorage 680 | BpfMapTypeReuseportSockarray 681 | BpfMapTypePercpuCgroupStorage 682 | BpfMapTypeQueue 683 | BpfMapTypeStack 684 | BpfMapTypeSkStorage 685 | BpfMapTypeDevmapHash 686 | BpfMapTypeStructOps 687 | BpfMapTypeRingbuf 688 | BpfMapTypeInodeStorage 689 | BpfMapTypeTaskStorage 690 | ) 691 | 692 | func (m MapType) MarshalJSON() ([]byte, error) { 693 | return []byte(`"` + m.String() + `"`), nil 694 | } 695 | 696 | func (m MapType) String() string { 697 | switch m { 698 | case BpfMapTypeUnspec: 699 | return "BpfMapTypeUnspec" 700 | case BpfMapTypeHash: 701 | return "BpfMapTypeHash" 702 | case BpfMapTypeArray: 703 | return "BpfMapTypeArray" 704 | case BpfMapTypeProgArray: 705 | return "BpfMapTypeProgArray" 706 | case BpfMapTypePerfEventArray: 707 | return "BpfMapTypePerfEventArray" 708 | case BpfMapTypePercpuHash: 709 | return "BpfMapTypePercpuHash" 710 | case BpfMapTypePercpuArray: 711 | return "BpfMapTypePercpuArray" 712 | case BpfMapTypeStackTrace: 713 | return "BpfMapTypeStackTrace" 714 | case BpfMapTypeCgroupArray: 715 | return "BpfMapTypeCgroupArray" 716 | case BpfMapTypeLruHash: 717 | return "BpfMapTypeLruHash" 718 | case BpfMapTypeLruPercpuHash: 719 | return "BpfMapTypeLruPercpuHash" 720 | case BpfMapTypeLpmTrie: 721 | return "BpfMapTypeLpmTrie" 722 | case BpfMapTypeArrayOfMaps: 723 | return "BpfMapTypeArrayOfMaps" 724 | case BpfMapTypeHashOfMaps: 725 | return "BpfMapTypeHashOfMaps" 726 | case BpfMapTypeDevmap: 727 | return "BpfMapTypeDevmap" 728 | case BpfMapTypeSockmap: 729 | return "BpfMapTypeSockmap" 730 | case BpfMapTypeCpumap: 731 | return "BpfMapTypeCpumap" 732 | case BpfMapTypeXskmap: 733 | return "BpfMapTypeXskmap" 734 | case BpfMapTypeSockhash: 735 | return "BpfMapTypeSockhash" 736 | case BpfMapTypeCgroupStorage: 737 | return "BpfMapTypeCgroupStorage" 738 | case BpfMapTypeReuseportSockarray: 739 | return "BpfMapTypeReuseportSockarray" 740 | case BpfMapTypePercpuCgroupStorage: 741 | return "BpfMapTypePercpuCgroupStorage" 742 | case BpfMapTypeQueue: 743 | return "BpfMapTypeQueue" 744 | case BpfMapTypeStack: 745 | return "BpfMapTypeStack" 746 | case BpfMapTypeSkStorage: 747 | return "BpfMapTypeSkStorage" 748 | case BpfMapTypeDevmapHash: 749 | return "BpfMapTypeDevmapHash" 750 | case BpfMapTypeStructOps: 751 | return "BpfMapTypeStructOps" 752 | case BpfMapTypeRingbuf: 753 | return "BpfMapTypeRingbuf" 754 | case BpfMapTypeInodeStorage: 755 | return "BpfMapTypeInodeStorage" 756 | case BpfMapTypeTaskStorage: 757 | return "BpfMapTypeTaskStorage" 758 | } 759 | return fmt.Sprintf("MapType(%d)", m) 760 | } 761 | 762 | type ProgramType uint32 763 | 764 | const ( 765 | BpfProgTypeUnspec ProgramType = iota 766 | BpfProgTypeSocketFilter 767 | BpfProgTypeKprobe 768 | BpfProgTypeSchedCls 769 | BpfProgTypeSchedAct 770 | BpfProgTypeTracepoint 771 | BpfProgTypeXdp 772 | BpfProgTypePerfEvent 773 | BpfProgTypeCgroupSkb 774 | BpfProgTypeCgroupSock 775 | BpfProgTypeLwtIn 776 | BpfProgTypeLwtOut 777 | BpfProgTypeLwtXmit 778 | BpfProgTypeSockOps 779 | BpfProgTypeSkSkb 780 | BpfProgTypeCgroupDevice 781 | BpfProgTypeSkMsg 782 | BpfProgTypeRawTracepoint 783 | BpfProgTypeCgroupSockAddr 784 | BpfProgTypeLwtSeg6local 785 | BpfProgTypeLircMode2 786 | BpfProgTypeSkReuseport 787 | BpfProgTypeFlowDissector 788 | BpfProgTypeCgroupSysctl 789 | BpfProgTypeRawTracepointWritable 790 | BpfProgTypeCgroupSockopt 791 | BpfProgTypeTracing 792 | BpfProgTypeStructOps 793 | BpfProgTypeExt 794 | BpfProgTypeLsm 795 | BpfProgTypeSkLookup 796 | ) 797 | 798 | func (p ProgramType) MarshalJSON() ([]byte, error) { 799 | return []byte(`"` + p.String() + `"`), nil 800 | } 801 | 802 | func (p ProgramType) String() string { 803 | switch p { 804 | case BpfProgTypeUnspec: 805 | return "BpfProgTypeUnspec" 806 | case BpfProgTypeSocketFilter: 807 | return "BpfProgTypeSocketFilter" 808 | case BpfProgTypeKprobe: 809 | return "BpfProgTypeKprobe" 810 | case BpfProgTypeSchedCls: 811 | return "BpfProgTypeSchedCls" 812 | case BpfProgTypeSchedAct: 813 | return "BpfProgTypeSchedAct" 814 | case BpfProgTypeTracepoint: 815 | return "BpfProgTypeTracepoint" 816 | case BpfProgTypeXdp: 817 | return "BpfProgTypeXdp" 818 | case BpfProgTypePerfEvent: 819 | return "BpfProgTypePerfEvent" 820 | case BpfProgTypeCgroupSkb: 821 | return "BpfProgTypeCgroupSkb" 822 | case BpfProgTypeCgroupSock: 823 | return "BpfProgTypeCgroupSock" 824 | case BpfProgTypeLwtIn: 825 | return "BpfProgTypeLwtIn" 826 | case BpfProgTypeLwtOut: 827 | return "BpfProgTypeLwtOut" 828 | case BpfProgTypeLwtXmit: 829 | return "BpfProgTypeLwtXmit" 830 | case BpfProgTypeSockOps: 831 | return "BpfProgTypeSockOps" 832 | case BpfProgTypeSkSkb: 833 | return "BpfProgTypeSkSkb" 834 | case BpfProgTypeCgroupDevice: 835 | return "BpfProgTypeCgroupDevice" 836 | case BpfProgTypeSkMsg: 837 | return "BpfProgTypeSkMsg" 838 | case BpfProgTypeRawTracepoint: 839 | return "BpfProgTypeRawTracepoint" 840 | case BpfProgTypeCgroupSockAddr: 841 | return "BpfProgTypeCgroupSockAddr" 842 | case BpfProgTypeLwtSeg6local: 843 | return "BpfProgTypeLwtSeg6local" 844 | case BpfProgTypeLircMode2: 845 | return "BpfProgTypeLircMode2" 846 | case BpfProgTypeSkReuseport: 847 | return "BpfProgTypeSkReuseport" 848 | case BpfProgTypeFlowDissector: 849 | return "BpfProgTypeFlowDissector" 850 | case BpfProgTypeCgroupSysctl: 851 | return "BpfProgTypeCgroupSysctl" 852 | case BpfProgTypeRawTracepointWritable: 853 | return "BpfProgTypeRawTracepointWritable" 854 | case BpfProgTypeCgroupSockopt: 855 | return "BpfProgTypeCgroupSockopt" 856 | case BpfProgTypeTracing: 857 | return "BpfProgTypeTracing" 858 | case BpfProgTypeStructOps: 859 | return "BpfProgTypeStructOps" 860 | case BpfProgTypeExt: 861 | return "BpfProgTypeExt" 862 | case BpfProgTypeLsm: 863 | return "BpfProgTypeLsm" 864 | case BpfProgTypeSkLookup: 865 | return "BpfProgTypeSkLookup" 866 | } 867 | return fmt.Sprintf("ProgramType(%d)", p) 868 | } 869 | 870 | type AttachType uint32 871 | 872 | const ( 873 | BpfCgroupInetIngress AttachType = iota + 1 874 | BpfCgroupInetEgress 875 | BpfCgroupInetSockCreate 876 | BpfCgroupSockOps 877 | BpfSkSkbStreamParser 878 | BpfSkSkbStreamVerdict 879 | BpfCgroupDevice 880 | BpfSkMsgVerdict 881 | BpfCgroupInet4Bind 882 | BpfCgroupInet6Bind 883 | BpfCgroupInet4Connect 884 | BpfCgroupInet6Connect 885 | BpfCgroupInet4PostBind 886 | BpfCgroupInet6PostBind 887 | BpfCgroupUdp4Sendmsg 888 | BpfCgroupUdp6Sendmsg 889 | BpfLircMode2 890 | BpfFlowDissector 891 | BpfCgroupSysctl 892 | BpfCgroupUdp4Recvmsg 893 | BpfCgroupUdp6Recvmsg 894 | BpfCgroupGetsockopt 895 | BpfCgroupSetsockopt 896 | BpfTraceRawTp 897 | BpfTraceFentry 898 | BpfTraceFexit 899 | BpfModifyReturn 900 | BpfLsmMac 901 | BpfTraceIter 902 | BpfCgroupInet4Getpeername 903 | BpfCgroupInet6Getpeername 904 | BpfCgroupInet4Getsockname 905 | BpfCgroupInet6Getsockname 906 | BpfXdpDevmap 907 | BpfCgroupInetSockRelease 908 | BpfXdpCpumap 909 | BpfSkLookup 910 | BpfXdp 911 | BpfSkSkbVerdict 912 | ) 913 | 914 | func NewAttachType(progType ProgramType, attachType uint32) AttachType { 915 | if attachType > 0 { 916 | return AttachType(attachType) 917 | } 918 | 919 | switch progType { 920 | case BpfProgTypeCgroupDevice, BpfProgTypeCgroupSock, BpfProgTypeCgroupSockopt, BpfProgTypeCgroupSkb, BpfProgTypeCgroupSysctl, BpfProgTypeCgroupSockAddr: 921 | return BpfCgroupInetIngress 922 | } 923 | return 0 924 | } 925 | 926 | func (a AttachType) MarshalJSON() ([]byte, error) { 927 | return []byte(`"` + a.String() + `"`), nil 928 | } 929 | 930 | func (a AttachType) String() string { 931 | switch a { 932 | case BpfCgroupInetIngress: 933 | return "BpfCgroupInetIngress" 934 | case BpfCgroupInetEgress: 935 | return "BpfCgroupInetEgress" 936 | case BpfCgroupInetSockCreate: 937 | return "BpfCgroupInetSockCreate" 938 | case BpfCgroupSockOps: 939 | return "BpfCgroupSockOps" 940 | case BpfSkSkbStreamParser: 941 | return "BpfSkSkbStreamParser" 942 | case BpfSkSkbStreamVerdict: 943 | return "BpfSkSkbStreamVerdict" 944 | case BpfCgroupDevice: 945 | return "BpfCgroupDevice" 946 | case BpfSkMsgVerdict: 947 | return "BpfSkMsgVerdict" 948 | case BpfCgroupInet4Bind: 949 | return "BpfCgroupInet4Bind" 950 | case BpfCgroupInet6Bind: 951 | return "BpfCgroupInet6Bind" 952 | case BpfCgroupInet4Connect: 953 | return "BpfCgroupInet4Connect" 954 | case BpfCgroupInet6Connect: 955 | return "BpfCgroupInet6Connect" 956 | case BpfCgroupInet4PostBind: 957 | return "BpfCgroupInet4PostBind" 958 | case BpfCgroupInet6PostBind: 959 | return "BpfCgroupInet6PostBind" 960 | case BpfCgroupUdp4Sendmsg: 961 | return "BpfCgroupUdp4Sendmsg" 962 | case BpfCgroupUdp6Sendmsg: 963 | return "BpfCgroupUdp6Sendmsg" 964 | case BpfLircMode2: 965 | return "BpfLircMode2" 966 | case BpfFlowDissector: 967 | return "BpfFlowDissector" 968 | case BpfCgroupSysctl: 969 | return "BpfCgroupSysctl" 970 | case BpfCgroupUdp4Recvmsg: 971 | return "BpfCgroupUdp4Recvmsg" 972 | case BpfCgroupUdp6Recvmsg: 973 | return "BpfCgroupUdp6Recvmsg" 974 | case BpfCgroupGetsockopt: 975 | return "BpfCgroupGetsockopt" 976 | case BpfCgroupSetsockopt: 977 | return "BpfCgroupSetsockopt" 978 | case BpfTraceRawTp: 979 | return "BpfTraceRawTp" 980 | case BpfTraceFentry: 981 | return "BpfTraceFentry" 982 | case BpfTraceFexit: 983 | return "BpfTraceFexit" 984 | case BpfModifyReturn: 985 | return "BpfModifyReturn" 986 | case BpfLsmMac: 987 | return "BpfLsmMac" 988 | case BpfTraceIter: 989 | return "BpfTraceIter" 990 | case BpfCgroupInet4Getpeername: 991 | return "BpfCgroupInet4Getpeername" 992 | case BpfCgroupInet6Getpeername: 993 | return "BpfCgroupInet6Getpeername" 994 | case BpfCgroupInet4Getsockname: 995 | return "BpfCgroupInet4Getsockname" 996 | case BpfCgroupInet6Getsockname: 997 | return "BpfCgroupInet6Getsockname" 998 | case BpfXdpDevmap: 999 | return "BpfXdpDevmap" 1000 | case BpfCgroupInetSockRelease: 1001 | return "BpfCgroupInetSockRelease" 1002 | case BpfXdpCpumap: 1003 | return "BpfXdpCpumap" 1004 | case BpfSkLookup: 1005 | return "BpfSkLookup" 1006 | case BpfXdp: 1007 | return "BpfXdp" 1008 | case BpfSkSkbVerdict: 1009 | return "BpfSkSkbVerdict" 1010 | } 1011 | return fmt.Sprintf("AttachType(%d)", a) 1012 | } 1013 | -------------------------------------------------------------------------------- /pkg/model/event.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 GUILLAUME FOURNIER 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package model 18 | 19 | import ( 20 | "bytes" 21 | "fmt" 22 | "time" 23 | 24 | "github.com/pkg/errors" 25 | ) 26 | 27 | type Event struct { 28 | Timestamp time.Time `json:"timestamp"` 29 | Command BPFCmd `json:"command"` 30 | Map *Map `json:"map,omitempty"` 31 | Program *Program `json:"program,omitempty"` 32 | Comm string `json:"comm,omitempty"` 33 | } 34 | 35 | func (e Event) String() string { 36 | s := fmt.Sprintf("cmd:%s comm:%s", e.Command, e.Comm) 37 | if e.Map != nil && e.Map.ID > 0 { 38 | s += fmt.Sprintf(" map:%s", e.Map) 39 | } 40 | if e.Program != nil && e.Program.ID > 0 { 41 | s += fmt.Sprintf(" prog:%s", e.Program) 42 | } 43 | return s 44 | } 45 | 46 | var ( 47 | // ErrNotEnoughData is used to notify that not enough data was read from the perf buffer 48 | ErrNotEnoughData = errors.New("not enough data") 49 | ) 50 | 51 | func (e *Event) UnmarshalBinary(data []byte, bootTime time.Time) (int, error) { 52 | var read int 53 | var err error 54 | 55 | if len(data) < 16 { 56 | return 0, ErrNotEnoughData 57 | } 58 | 59 | e.Timestamp = bootTime.Add(time.Duration(ByteOrder.Uint64(data[0:8])) * time.Nanosecond) 60 | e.Command = BPFCmd(ByteOrder.Uint32(data[8:12])) 61 | // padding 62 | cursor := 16 63 | 64 | e.Map = &Map{} 65 | if read, err = e.Map.UnmarshalBinary(data[cursor:]); err != nil { 66 | return 0, err 67 | } 68 | cursor += read 69 | if e.Map.ID == 0 { 70 | e.Map = nil 71 | } 72 | 73 | e.Program = &Program{} 74 | if read, err = e.Program.UnmarshalBinary(data[cursor:]); err != nil { 75 | return 0, err 76 | } 77 | cursor += read 78 | if e.Program.ID == 0 { 79 | e.Program = nil 80 | } 81 | 82 | if len(data) < cursor+16 { 83 | return 0, ErrNotEnoughData 84 | } 85 | 86 | e.Comm = bytes.NewBuffer(bytes.Trim(data[cursor:cursor+16], "\x00")).String() 87 | return cursor + 16, nil 88 | } 89 | 90 | type Map struct { 91 | ID uint32 `json:"id"` 92 | Type MapType `json:"type"` 93 | Name string `json:"name"` 94 | } 95 | 96 | func (m Map) String() string { 97 | return fmt.Sprintf("id:%d name:%s type:%s", m.ID, m.Name, m.Type) 98 | } 99 | 100 | func (m *Map) UnmarshalBinary(data []byte) (int, error) { 101 | if len(data) < 24 { 102 | return 0, ErrNotEnoughData 103 | } 104 | m.ID = ByteOrder.Uint32(data[0:4]) 105 | m.Type = MapType(ByteOrder.Uint32(data[4:8])) 106 | m.Name = bytes.NewBuffer(bytes.Trim(data[8:24], "\x00")).String() 107 | return 24, nil 108 | } 109 | 110 | type Program struct { 111 | ID uint32 `json:"id"` 112 | Type ProgramType `json:"type"` 113 | AttachType AttachType `json:"attach_type,omitempty"` 114 | Helpers []HelperFunc `json:"helpers,omitempty"` 115 | Name string `json:"name"` 116 | } 117 | 118 | func (p Program) String() string { 119 | return fmt.Sprintf("id:%d name:%s type:%s attach_type:%d helpers:%s", p.ID, p.Name, p.Type, p.AttachType, p.Helpers) 120 | } 121 | 122 | func (p *Program) UnmarshalBinary(data []byte) (int, error) { 123 | p.ID = ByteOrder.Uint32(data[0:4]) 124 | p.Type = ProgramType(ByteOrder.Uint32(data[4:8])) 125 | p.AttachType = NewAttachType(p.Type, ByteOrder.Uint32(data[8:12])) 126 | // padding 127 | helpers := []uint64{0, 0, 0} 128 | helpers[0] = ByteOrder.Uint64(data[16:24]) 129 | helpers[1] = ByteOrder.Uint64(data[24:32]) 130 | helpers[2] = ByteOrder.Uint64(data[32:40]) 131 | p.Helpers = parseHelpers(helpers) 132 | p.Name = bytes.NewBuffer(bytes.Trim(data[40:56], "\x00")).String() 133 | return 56, nil 134 | } 135 | 136 | func parseHelpers(helpers []uint64) []HelperFunc { 137 | var rep []HelperFunc 138 | var add bool 139 | 140 | if len(helpers) < 3 { 141 | return rep 142 | } 143 | 144 | for i := 0; i < 192; i++ { 145 | add = false 146 | if i < 64 { 147 | if helpers[0]&(1< %s", generateNodeID(prog.SectionName), generateNodeID(m)), 166 | Color: colors[int(prog.Type)%len(colors)], 167 | }) 168 | } 169 | } 170 | return data 171 | } 172 | 173 | func generateNodeID(section string) string { 174 | var id string 175 | for _, b := range blake2b.Sum256([]byte(section)) { 176 | id += fmt.Sprintf("%v", b) 177 | } 178 | return id 179 | } 180 | -------------------------------------------------------------------------------- /pkg/monitor/kernel/kernel.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 GUILLAUME FOURNIER 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package kernel 18 | 19 | import ( 20 | "fmt" 21 | "strings" 22 | 23 | "github.com/cobaugh/osrelease" 24 | "github.com/pkg/errors" 25 | ) 26 | 27 | // Version defines a kernel version helper 28 | type Version struct { 29 | osRelease map[string]string 30 | } 31 | 32 | func (k *Version) String() string { 33 | return fmt.Sprintf("kernel %v", k.osRelease) 34 | } 35 | 36 | // NewKernelVersion returns a new kernel version helper 37 | func NewKernelVersion() (*Version, error) { 38 | osReleasePaths := []string{ 39 | osrelease.EtcOsRelease, 40 | osrelease.UsrLibOsRelease, 41 | } 42 | 43 | var release map[string]string 44 | var err error 45 | for _, osReleasePath := range osReleasePaths { 46 | release, err = osrelease.ReadFile(osReleasePath) 47 | if err == nil { 48 | return &Version{ 49 | osRelease: release, 50 | }, nil 51 | } 52 | } 53 | 54 | return nil, errors.New("failed to detect operating system version") 55 | } 56 | 57 | // IsRH7Kernel returns whether the kernel is a rh7 kernel 58 | func (k *Version) IsRH7Kernel() bool { 59 | return (k.osRelease["ID"] == "centos" || k.osRelease["ID"] == "rhel") && k.osRelease["VERSION_ID"] == "7" 60 | } 61 | 62 | // IsRH8Kernel returns whether the kernel is a rh8 kernel 63 | func (k *Version) IsRH8Kernel() bool { 64 | return k.osRelease["PLATFORM_ID"] == "platform:el8" 65 | } 66 | 67 | // IsSuseKernel returns whether the kernel is a suse kernel 68 | func (k *Version) IsSuseKernel() bool { 69 | return k.osRelease["ID"] == "sles" || k.osRelease["ID"] == "opensuse-leap" 70 | } 71 | 72 | // IsSLES12Kernel returns whether the kernel is a sles 12 kernel 73 | func (k *Version) IsSLES12Kernel() bool { 74 | return k.IsSuseKernel() && strings.HasPrefix(k.osRelease["VERSION_ID"], "12") 75 | } 76 | 77 | // IsSLES15Kernel returns whether the kernel is a sles 15 kernel 78 | func (k *Version) IsSLES15Kernel() bool { 79 | return k.IsSuseKernel() && strings.HasPrefix(k.osRelease["VERSION_ID"], "15") 80 | } 81 | 82 | // IsOracleUEKKernel returns whether the kernel is an oracle uek kernel 83 | func (k *Version) IsOracleUEKKernel() bool { 84 | return k.osRelease["ID"] == "ol" 85 | } 86 | -------------------------------------------------------------------------------- /pkg/monitor/manager.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 GUILLAUME FOURNIER 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package monitor 18 | 19 | import ( 20 | "bytes" 21 | "math" 22 | "os" 23 | 24 | "github.com/DataDog/ebpf" 25 | "github.com/DataDog/ebpf/manager" 26 | "github.com/pkg/errors" 27 | "golang.org/x/sys/unix" 28 | 29 | "github.com/Gui774ume/ebpfkit-monitor/pkg/assets" 30 | ) 31 | 32 | const ( 33 | // EBPFKitMonitorID is used to identify ebpfkit-monitor's probes 34 | EBPFKitMonitorID = "ebpfkitMonitor" 35 | ) 36 | 37 | func (m *Monitor) getAllProbes() []*manager.Probe { 38 | attrProbes := []*manager.Probe{ 39 | {Section: "tracepoint/sched/sched_process_exec", UID: EBPFKitMonitorID}, 40 | {Section: "tracepoint/sched/sched_process_fork", UID: EBPFKitMonitorID}, 41 | {Section: "tracepoint/sched/sched_process_exit", UID: EBPFKitMonitorID}, 42 | {Section: "kprobe/security_bpf", UID: EBPFKitMonitorID}, 43 | {Section: "kprobe/security_bpf_map", UID: EBPFKitMonitorID}, 44 | {Section: "kprobe/security_bpf_prog", UID: EBPFKitMonitorID}, 45 | {Section: "kprobe/check_helper_call", MatchFuncName: "check_helper_call", UID: EBPFKitMonitorID}, 46 | } 47 | 48 | // Make sure to append the bpf probe at the end, otherwise there is a race condition that might prevent the monitor 49 | // from loading further eBPF programs 50 | attrProbes = append(attrProbes, ExpandSyscallProbes(&manager.Probe{ 51 | UID: EBPFKitMonitorID, 52 | SyscallFuncName: "bpf", 53 | }, EntryAndExit)...) 54 | 55 | return attrProbes 56 | } 57 | 58 | func (m *Monitor) getManagerOptions() manager.Options { 59 | options := manager.Options{ 60 | // DefaultKProbeMaxActive is the maximum number of active kretprobe at a given time 61 | DefaultKProbeMaxActive: 512, 62 | 63 | VerifierOptions: ebpf.CollectionOptions{ 64 | Programs: ebpf.ProgramOptions{ 65 | // LogSize is the size of the log buffer given to the verifier. Give it a big enough (2 * 1024 * 1024) 66 | // value so that all our programs fit. If the verifier ever outputs a `no space left on device` error, 67 | // we'll need to increase this value. 68 | LogSize: 2097152, 69 | }, 70 | }, 71 | 72 | // Extend RLIMIT_MEMLOCK (8) size 73 | // On some systems, the default for RLIMIT_MEMLOCK may be as low as 64 bytes. 74 | // This will result in an EPERM (Operation not permitted) error, when trying to create an eBPF map 75 | // using bpf(2) with BPF_MAP_CREATE. 76 | // 77 | // We are setting the limit to infinity until we have a better handle on the true requirements. 78 | RLimit: &unix.Rlimit{ 79 | Cur: math.MaxUint64, 80 | Max: math.MaxUint64, 81 | }, 82 | } 83 | 84 | if len(m.options.AllowedProcesses) > 0 { 85 | options.ConstantEditors = append(options.ConstantEditors, manager.ConstantEditor{ 86 | Name: "protect_bpf", 87 | Value: uint64(1), 88 | }) 89 | } 90 | 91 | return options 92 | } 93 | 94 | func (m *Monitor) setupEbpfManager(executable string) error { 95 | // set new manager 96 | m.manager = &manager.Manager{ 97 | Probes: m.getAllProbes(), 98 | Maps: []*manager.Map{ 99 | {Name: "allowed_binaries", Contents: m.options.GetAllowedProcessesKV(executable)}, 100 | }, 101 | PerfMaps: []*manager.PerfMap{ 102 | { 103 | Map: manager.Map{ 104 | Name: "events", 105 | }, 106 | PerfMapOptions: manager.PerfMapOptions{ 107 | PerfRingBufferSize: 8192 * os.Getpagesize(), 108 | DataHandler: m.eventsHandler, 109 | }, 110 | }, 111 | }, 112 | } 113 | 114 | // retrieve assets 115 | buf, err := assets.Asset("/probe.o") 116 | if err != nil { 117 | return errors.Wrap(err, "failed to retrieve eBPF bytecode") 118 | } 119 | 120 | // init manager 121 | if err = m.manager.InitWithOptions(bytes.NewReader(buf), m.getManagerOptions()); err != nil { 122 | return errors.Wrap(err, "failed to init eBPF manager") 123 | } 124 | return nil 125 | } 126 | -------------------------------------------------------------------------------- /pkg/monitor/monitor.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 GUILLAUME FOURNIER 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package monitor 18 | 19 | import ( 20 | "encoding/json" 21 | "fmt" 22 | "io/ioutil" 23 | "os" 24 | "strings" 25 | "time" 26 | 27 | "github.com/DataDog/ebpf" 28 | "github.com/DataDog/ebpf/asm" 29 | "github.com/DataDog/ebpf/manager" 30 | "github.com/DataDog/gopsutil/host" 31 | "github.com/pkg/errors" 32 | "github.com/sirupsen/logrus" 33 | 34 | "github.com/Gui774ume/ebpfkit-monitor/pkg/model" 35 | ) 36 | 37 | // Monitor is the main Monitor structure 38 | type Monitor struct { 39 | collectionSpec *ebpf.CollectionSpec 40 | maxProgLength int 41 | maxProgsPerMap int 42 | bootTime time.Time 43 | outputFile *os.File 44 | 45 | // eBPF helpers 46 | helperTranslation map[string]asm.BuiltinFunc 47 | 48 | // processes assets 49 | programTypes map[ebpf.ProgramType]map[string]int 50 | programMaps map[string]map[string]int 51 | programHelpers map[string]map[asm.BuiltinFunc]int 52 | helpers map[asm.BuiltinFunc]map[string]int 53 | mapTypes map[ebpf.MapType]map[string]int 54 | mapPrograms map[string]map[string]int 55 | 56 | // runtime monitoring 57 | manager *manager.Manager 58 | options model.EBPFKitOptions 59 | } 60 | 61 | func (m *Monitor) parseAsset(asset string) error { 62 | if _, err := os.Stat(asset); err != nil { 63 | return err 64 | } 65 | 66 | f, err := os.Open(asset) 67 | if err != nil { 68 | return err 69 | } 70 | 71 | m.collectionSpec, err = ebpf.LoadCollectionSpecFromReader(f) 72 | if err != nil { 73 | return err 74 | } 75 | return nil 76 | } 77 | 78 | // NewMonitor returns a new Monitor instance 79 | func NewMonitor(options model.EBPFKitOptions) (*Monitor, error) { 80 | // Set log level 81 | logrus.SetLevel(options.LogLevel) 82 | 83 | // Get boot time 84 | bt, err := host.BootTime() 85 | if err != nil { 86 | return nil, err 87 | } 88 | 89 | m := &Monitor{ 90 | helperTranslation: make(map[string]asm.BuiltinFunc), 91 | programTypes: make(map[ebpf.ProgramType]map[string]int), 92 | programMaps: make(map[string]map[string]int), 93 | programHelpers: make(map[string]map[asm.BuiltinFunc]int), 94 | helpers: make(map[asm.BuiltinFunc]map[string]int), 95 | mapTypes: make(map[ebpf.MapType]map[string]int), 96 | mapPrograms: make(map[string]map[string]int), 97 | options: options, 98 | bootTime: time.Unix(int64(bt), 0), 99 | } 100 | 101 | // build eBPF helper translation 102 | var i int 103 | var helper asm.BuiltinFunc 104 | for { 105 | helper = asm.BuiltinFunc(i) 106 | if !strings.HasPrefix(helper.String(), "BuiltinFunc") { 107 | m.helperTranslation[model.HelperFunc(helper).String()] = helper 108 | i++ 109 | } else { 110 | break 111 | } 112 | } 113 | 114 | // parse asset 115 | if len(options.EBPFAssetPath) > 0 { 116 | if err := m.parseAsset(options.EBPFAssetPath); err != nil { 117 | return nil, errors.Wrapf(err, "couldn't parse asset %s", options.EBPFAssetPath) 118 | } 119 | // process eBPF assets 120 | m.processAssets() 121 | } 122 | 123 | // create output file if applicable 124 | if len(options.OutputDirectory) > 0 { 125 | m.outputFile, err = ioutil.TempFile(options.OutputDirectory, "ebpfkit-monitor-*.json") 126 | if err != nil { 127 | return nil, errors.Wrapf(err, "failed to generate output file") 128 | } 129 | } 130 | return m, nil 131 | } 132 | 133 | // ShowProgram prints information about the provided program section. If no section is provided, all the programs will 134 | // be displayed. 135 | func (m *Monitor) ShowProgram(section string, dumpByteCode bool, helper string, mapName string) error { 136 | // if a program section is provided, dump program info 137 | if len(section) != 0 { 138 | programSpec, ok := m.collectionSpec.Programs[section] 139 | if !ok { 140 | return errors.Errorf("%s section not found", section) 141 | } 142 | 143 | if len(helper) > 0 { 144 | if m.programHelpers[programSpec.SectionName][m.helperTranslation[helper]] <= 0 { 145 | return errors.Errorf("section %s doesn't use eBPF helper %s", section, helper) 146 | } 147 | } 148 | 149 | if len(mapName) > 0 { 150 | if m.programMaps[programSpec.SectionName][mapName] <= 0 { 151 | return errors.Errorf("section %s doesn't use map %s", section, mapName) 152 | } 153 | } 154 | 155 | m.printProgramSpec(programSpec, dumpByteCode) 156 | return nil 157 | } 158 | 159 | var selectedSections []string 160 | var shouldFilter bool 161 | // select programs by helpers 162 | if len(helper) > 0 { 163 | shouldFilter = true 164 | for prog := range m.helpers[m.helperTranslation[helper]] { 165 | if len(mapName) > 0 { 166 | if m.programMaps[prog][mapName] > 0 { 167 | selectedSections = append(selectedSections, prog) 168 | } 169 | } else { 170 | selectedSections = append(selectedSections, prog) 171 | } 172 | } 173 | } else if len(mapName) > 0 { 174 | shouldFilter = true 175 | for prog := range m.mapPrograms[mapName] { 176 | selectedSections = append(selectedSections, prog) 177 | } 178 | } 179 | 180 | CollectionSpec: 181 | for _, spec := range m.collectionSpec.Programs { 182 | if shouldFilter { 183 | selectedSection := false 184 | for _, section := range selectedSections { 185 | if section == spec.SectionName { 186 | selectedSection = true 187 | } 188 | } 189 | if !selectedSection { 190 | continue CollectionSpec 191 | } 192 | } 193 | m.printProgramSpec(spec, dumpByteCode) 194 | } 195 | return nil 196 | } 197 | 198 | func (m *Monitor) printProgramSpec(spec *ebpf.ProgramSpec, dumpByteCode bool) { 199 | fmt.Printf("%s\n", spec.Name) 200 | fmt.Printf(" SectionName: %s\n", spec.SectionName) 201 | fmt.Printf(" Type: %s\n", model.ProgramType(spec.Type)) 202 | fmt.Printf(" InstructionsCount: %d\n", len(spec.Instructions)) 203 | fmt.Printf(" AttachType: %d\n", model.AttachType(spec.AttachType)) 204 | fmt.Printf(" License: %s\n", spec.License) 205 | fmt.Printf(" KernelVersion: %d\n", spec.KernelVersion) 206 | fmt.Printf(" ByteOrder: %s\n", spec.ByteOrder) 207 | 208 | // Print list of eBPF helpers 209 | if len(m.programHelpers[spec.SectionName]) > 0 { 210 | fmt.Println(" Helpers:") 211 | } 212 | for helper, count := range m.programHelpers[spec.SectionName] { 213 | fmt.Printf(" - %s: %d\n", model.HelperFunc(helper), count) 214 | } 215 | 216 | // Print list of maps 217 | if len(m.programMaps[spec.SectionName]) > 0 { 218 | fmt.Println(" Maps:") 219 | } 220 | for m, count := range m.programMaps[spec.SectionName] { 221 | fmt.Printf(" - %s: %d\n", m, count) 222 | } 223 | 224 | if dumpByteCode { 225 | fmt.Printf(" Bytecode:\n%s", spec.Instructions[1:]) 226 | } 227 | fmt.Println() 228 | } 229 | 230 | // ShowMap prints information about the provided map section. If no section is provided, all the maps will 231 | // be displayed. 232 | func (m *Monitor) ShowMap(section string) error { 233 | // if a map section is provided, dump map info 234 | if len(section) != 0 { 235 | spec, ok := m.collectionSpec.Maps[section] 236 | if !ok { 237 | return errors.Errorf("%s section not found in %s", section, section) 238 | } 239 | m.printMapSpec(spec, section) 240 | return nil 241 | } 242 | 243 | // if not, dump all maps 244 | for sec, spec := range m.collectionSpec.Maps { 245 | m.printMapSpec(spec, sec) 246 | } 247 | return nil 248 | } 249 | 250 | func (m *Monitor) printMapSpec(spec *ebpf.MapSpec, section string) { 251 | fmt.Printf("%s\n", spec.Name) 252 | fmt.Printf(" SectionName: %s\n", section) 253 | fmt.Printf(" Type: %s\n", model.MapType(spec.Type)) 254 | fmt.Printf(" Flags: %d\n", spec.Flags) 255 | fmt.Printf(" KeySize: %d\n", spec.KeySize) 256 | fmt.Printf(" ValueSize: %d\n", spec.ValueSize) 257 | fmt.Printf(" MaxEntries: %d\n", spec.MaxEntries) 258 | 259 | if len(m.mapPrograms[spec.Name]) > 0 { 260 | fmt.Println(" Programs:") 261 | } 262 | for p, count := range m.mapPrograms[spec.Name] { 263 | fmt.Printf(" - %s: %d\n", p, count) 264 | } 265 | fmt.Println() 266 | } 267 | 268 | func (m *Monitor) ShowReport() error { 269 | fmt.Printf("Program types report (detected %d different types):\n", len(m.programTypes)) 270 | for t, progs := range m.programTypes { 271 | fmt.Printf(" - %s:\n", model.ProgramType(t)) 272 | for p := range progs { 273 | fmt.Printf(" * %s\n", p) 274 | } 275 | } 276 | fmt.Printf("\n\n") 277 | 278 | fmt.Printf("eBPF helpers report (detected %d different helpers):\n", len(m.programHelpers)) 279 | for helper, progs := range m.helpers { 280 | fmt.Printf(" - %s:\n", model.HelperFunc(helper)) 281 | for p, count := range progs { 282 | fmt.Printf(" * %s: %d\n", p, count) 283 | } 284 | } 285 | fmt.Printf("\n\n") 286 | 287 | fmt.Printf("Map types report (detected %d different types):\n", len(m.mapTypes)) 288 | for t, maps := range m.mapTypes { 289 | fmt.Printf(" - %s:\n", model.MapType(t)) 290 | for mp := range maps { 291 | fmt.Printf(" * %s\n", mp) 292 | for p, count := range m.mapPrograms[mp] { 293 | fmt.Printf(" + %s: %d\n", p, count) 294 | } 295 | } 296 | } 297 | return nil 298 | } 299 | 300 | func (m *Monitor) processAssets() { 301 | // Compute maps 302 | var mList []string 303 | for _, mp := range m.collectionSpec.Maps { 304 | mList = append(mList, mp.Name) 305 | if m.mapTypes[mp.Type] == nil { 306 | m.mapTypes[mp.Type] = map[string]int{} 307 | } 308 | m.mapTypes[mp.Type][mp.Name] = 1 309 | } 310 | 311 | // Compute programs 312 | for _, p := range m.collectionSpec.Programs { 313 | if m.programTypes[p.Type] == nil { 314 | m.programTypes[p.Type] = map[string]int{} 315 | } 316 | m.programTypes[p.Type][p.SectionName] = 1 317 | 318 | if len(p.Instructions) > m.maxProgLength { 319 | m.maxProgLength = len(p.Instructions) 320 | } 321 | for _, ins := range p.Instructions { 322 | if ins.OpCode.Class() == asm.JumpClass && ins.OpCode.JumpOp() == asm.Call && ins.Src != asm.PseudoCall { 323 | helper := asm.BuiltinFunc(ins.Constant) 324 | 325 | if m.helpers[helper] == nil { 326 | m.helpers[helper] = map[string]int{} 327 | } 328 | m.helpers[helper][p.SectionName] += 1 329 | 330 | if m.programHelpers[p.SectionName] == nil { 331 | m.programHelpers[p.SectionName] = map[asm.BuiltinFunc]int{} 332 | } 333 | m.programHelpers[p.SectionName][helper] += 1 334 | } 335 | if len(ins.Reference) > 0 && stringArrayContains(mList, ins.Reference) { 336 | if m.mapPrograms[ins.Reference] == nil { 337 | m.mapPrograms[ins.Reference] = map[string]int{} 338 | } 339 | m.mapPrograms[ins.Reference][p.SectionName] += 1 340 | 341 | if m.programMaps[p.SectionName] == nil { 342 | m.programMaps[p.SectionName] = map[string]int{} 343 | } 344 | m.programMaps[p.SectionName][ins.Reference] += 1 345 | } 346 | } 347 | } 348 | 349 | for _, progs := range m.mapPrograms { 350 | if len(progs) > m.maxProgsPerMap { 351 | m.maxProgsPerMap = len(progs) 352 | } 353 | } 354 | } 355 | 356 | func (m *Monitor) IsValidHelper(helper string) bool { 357 | if len(helper) == 0 { 358 | return true 359 | } 360 | return m.helperTranslation[helper] != 0 361 | } 362 | 363 | func (m *Monitor) Start() error { 364 | // fetch the current process executable path 365 | execPath, err := os.Readlink("/proc/self/exe") 366 | if err != nil { 367 | return errors.Wrap(err, "couldn't fetch the current process executable path") 368 | } 369 | 370 | // prepare eBPF manager 371 | if err := m.setupEbpfManager(execPath); err != nil { 372 | return errors.Wrap(err, "failed to setup eBPF manager") 373 | } 374 | 375 | // start manager 376 | if err := m.manager.Start(); err != nil { 377 | return errors.Wrap(err, "failed to start eBPF manager") 378 | } 379 | logrus.Info("ebpfkit-monitor is now running !") 380 | if m.outputFile != nil { 381 | logrus.Infof("writting captured events to: %s", m.outputFile.Name()) 382 | } 383 | return nil 384 | } 385 | 386 | func (m *Monitor) Stop() error { 387 | logrus.Info("shutting down ...") 388 | 389 | if err := m.manager.Stop(manager.CleanAll); err != nil { 390 | return errors.Wrap(err, "failed to stop eBPF manager") 391 | } 392 | if m.outputFile != nil { 393 | if err := m.outputFile.Close(); err != nil { 394 | return errors.Wrap(err, "failed to close output file") 395 | } 396 | } 397 | return nil 398 | } 399 | 400 | func (m *Monitor) eventsHandler(cpu int, data []byte, perfMap *manager.PerfMap, m2 *manager.Manager) { 401 | var evt model.Event 402 | if _, err := evt.UnmarshalBinary(data, m.bootTime); err != nil { 403 | logrus.Warnf("failed to decode event: %s", err) 404 | } 405 | logrus.Debugf("%s", evt) 406 | 407 | if m.outputFile != nil { 408 | data, err := json.Marshal(evt) 409 | if err != nil { 410 | logrus.Warnf("couldn't marshall event: %v", err) 411 | return 412 | } 413 | _, _ = m.outputFile.Write(data) 414 | _, _ = m.outputFile.Write([]byte{'\n'}) 415 | } 416 | return 417 | } 418 | -------------------------------------------------------------------------------- /pkg/monitor/syscall_helpers.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 GUILLAUME FOURNIER 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package monitor 18 | 19 | import ( 20 | "bytes" 21 | "strings" 22 | 23 | "github.com/DataDog/ebpf/manager" 24 | "github.com/pkg/errors" 25 | "golang.org/x/sys/unix" 26 | 27 | "github.com/Gui774ume/ebpfkit-monitor/pkg/monitor/kernel" 28 | ) 29 | 30 | // runtimeArch holds the CPU architecture of the running machine 31 | var runtimeArch string 32 | 33 | func resolveRuntimeArch() { 34 | var uname unix.Utsname 35 | if err := unix.Uname(&uname); err != nil { 36 | panic(err) 37 | } 38 | 39 | switch string(uname.Machine[:bytes.IndexByte(uname.Machine[:], 0)]) { 40 | case "x86_64": 41 | runtimeArch = "x64" 42 | case "aarch64": 43 | runtimeArch = "arm64" 44 | default: 45 | runtimeArch = "ia32" 46 | } 47 | } 48 | 49 | // currentKernelVersion is the current kernel version 50 | var currentKernelVersion *kernel.Version 51 | 52 | func resolveCurrentKernelVersion() error { 53 | var err error 54 | currentKernelVersion, err = kernel.NewKernelVersion() 55 | if err != nil { 56 | return errors.New("couldn't resolve kernel version") 57 | } 58 | return nil 59 | } 60 | 61 | // cache of the syscall prefix depending on kernel version 62 | var syscallPrefix string 63 | var ia32SyscallPrefix string 64 | 65 | func getSyscallPrefix() string { 66 | if syscallPrefix == "" { 67 | syscall, err := manager.GetSyscallFnName("open") 68 | if err != nil { 69 | return "__unknown__" 70 | } 71 | syscallPrefix = strings.ToLower(strings.TrimSuffix(syscall, "open")) 72 | if syscallPrefix != "sys_" { 73 | ia32SyscallPrefix = "__ia32_" 74 | } else { 75 | ia32SyscallPrefix = "compat_" 76 | } 77 | } 78 | 79 | return syscallPrefix 80 | } 81 | 82 | func getSyscallFnName(name string) string { 83 | return getSyscallPrefix() + name 84 | } 85 | 86 | func getIA32SyscallFnName(name string) string { 87 | return ia32SyscallPrefix + "sys_" + name 88 | } 89 | 90 | func getCompatSyscallFnName(name string) string { 91 | return ia32SyscallPrefix + "compat_sys_" + name 92 | } 93 | 94 | func expandKprobe(hookpoint string, syscallName string, flag int) []string { 95 | var sections []string 96 | if flag&Entry == Entry { 97 | sections = append(sections, "kprobe/"+hookpoint) 98 | } 99 | if flag&Exit == Exit { 100 | sections = append(sections, "kretprobe/"+hookpoint) 101 | } 102 | return sections 103 | } 104 | 105 | func expandSyscallSections(syscallName string, flag int, compat ...bool) []string { 106 | sections := expandKprobe(getSyscallFnName(syscallName), syscallName, flag) 107 | 108 | if runtimeArch == "x64" { 109 | if len(compat) > 0 && compat[0] && syscallPrefix != "sys_" { 110 | sections = append(sections, expandKprobe(getCompatSyscallFnName(syscallName), "", flag)...) 111 | } else { 112 | sections = append(sections, expandKprobe(getIA32SyscallFnName(syscallName), "", flag)...) 113 | } 114 | } 115 | 116 | return sections 117 | } 118 | 119 | const ( 120 | // Entry indicates that the entry kprobe should be expanded 121 | Entry = 1 << 0 122 | // Exit indicates that the exit kretprobe should be expanded 123 | Exit = 1 << 1 124 | // ExpandTime32 indicates that the _time32 suffix should be added to the provided probe if needed 125 | ExpandTime32 = 1 << 2 126 | 127 | // EntryAndExit indicates that both the entry kprobe and exit kretprobe should be expanded 128 | EntryAndExit = Entry | Exit 129 | ) 130 | 131 | // ExpandSyscallProbes returns the list of available hook probes for the syscall func name of the provided probe 132 | func ExpandSyscallProbes(probe *manager.Probe, flag int, compat ...bool) []*manager.Probe { 133 | var probes []*manager.Probe 134 | syscallName := probe.SyscallFuncName 135 | probe.SyscallFuncName = "" 136 | 137 | if len(runtimeArch) == 0 { 138 | resolveRuntimeArch() 139 | } 140 | 141 | if currentKernelVersion == nil { 142 | _ = resolveCurrentKernelVersion() 143 | } 144 | 145 | if flag&ExpandTime32 == ExpandTime32 { 146 | // check if _time32 should be expanded 147 | if getSyscallPrefix() == "sys_" { 148 | return probes 149 | } 150 | syscallName += "_time32" 151 | } 152 | 153 | for _, section := range expandSyscallSections(syscallName, flag, compat...) { 154 | probeCopy := probe.Copy() 155 | probeCopy.Section = section 156 | probes = append(probes, probeCopy) 157 | } 158 | 159 | return probes 160 | } 161 | 162 | // ExpandSyscallProbesSelector returns the list of a ProbesSelector required to query all the probes available for a syscall 163 | func ExpandSyscallProbesSelector(id manager.ProbeIdentificationPair, flag int, compat ...bool) []manager.ProbesSelector { 164 | var selectors []manager.ProbesSelector 165 | 166 | if len(runtimeArch) == 0 { 167 | resolveRuntimeArch() 168 | } 169 | 170 | if currentKernelVersion == nil { 171 | _ = resolveCurrentKernelVersion() 172 | } 173 | 174 | if flag&ExpandTime32 == ExpandTime32 { 175 | // check if _time32 should be expanded 176 | if getSyscallPrefix() == "sys_" { 177 | return selectors 178 | } 179 | id.Section += "_time32" 180 | } 181 | 182 | for _, section := range expandSyscallSections(id.Section, flag, compat...) { 183 | selector := &manager.ProbeSelector{ProbeIdentificationPair: manager.ProbeIdentificationPair{UID: id.UID, Section: section}} 184 | selectors = append(selectors, selector) 185 | } 186 | 187 | return selectors 188 | } 189 | -------------------------------------------------------------------------------- /pkg/monitor/utils.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 GUILLAUME FOURNIER 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package monitor 18 | 19 | func stringArrayContains(array []string, elem string) bool { 20 | for _, a := range array { 21 | if elem == a { 22 | return true 23 | } 24 | } 25 | return false 26 | } 27 | -------------------------------------------------------------------------------- /tools.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 GUILLAUME FOURNIER 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // +build tools 18 | 19 | package tools 20 | 21 | // Those imports are used to track tool dependencies. 22 | // This is the currently recommended approach: https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module 23 | 24 | import ( 25 | _ "github.com/shuLhan/go-bindata/cmd/go-bindata" 26 | ) 27 | --------------------------------------------------------------------------------