github.com/jayanthvn/pure-gobpf@v0.0.0-20230623131354-8d1d959d9e0b/pkg/ebpf_kprobe/kprobe.go (about) 1 // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"). 4 // You may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 //limitations under the License. 14 15 package ebpf_kprobe 16 17 import ( 18 "fmt" 19 "os" 20 "strconv" 21 "strings" 22 "syscall" 23 "unsafe" 24 25 "github.com/jayanthvn/pure-gobpf/pkg/logger" 26 "golang.org/x/sys/unix" 27 ) 28 29 const ( 30 kprobeSysEventsFile = "/sys/kernel/debug/tracing/kprobe_events" 31 ) 32 33 var log = logger.Get() 34 35 /* 36 p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS] : Set a probe 37 r[MAXACTIVE][:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS] : Set a return probe 38 -:[GRP/]EVENT 39 */ 40 // if event is nil, we pick funcName 41 func KprobeAttach(progFD int, eventName string, funcName string) error { 42 43 //var log = logger.Get() 44 45 if progFD <= 0 { 46 log.Infof("Invalid BPF prog FD %d", progFD) 47 return fmt.Errorf("Invalid BPF prog FD %d", progFD) 48 49 } 50 51 if len(eventName) == 0 { 52 eventName = funcName 53 } 54 55 // Register the Kprobe event 56 file, err := os.OpenFile(kprobeSysEventsFile, os.O_WRONLY|os.O_APPEND, 0) 57 if err != nil { 58 log.Infof("error opening kprobe_events file: %v", err) 59 return fmt.Errorf("error opening kprobe_events file: %v", err) 60 } 61 //defer file.Close() 62 63 eventString := fmt.Sprintf("p:kprobes/%s %s", eventName, funcName) 64 _, err = file.WriteString(eventString) 65 if err != nil { 66 log.Infof("error writing to kprobe_events file: %v", err) 67 return fmt.Errorf("error writing to kprobe_events file: %v", err) 68 } 69 70 //Get the Kprobe ID 71 kprobeIDpath := fmt.Sprintf("/sys/kernel/debug/tracing/events/kprobes/%s/id", eventName) 72 data, err := os.ReadFile(kprobeIDpath) 73 if err != nil { 74 log.Infof("Unable to read the kprobeID: %v", err) 75 return fmt.Errorf("Unable to read the kprobeID: %v", err) 76 } 77 id := strings.TrimSpace(string(data)) 78 eventID, err := strconv.Atoi(id) 79 if err != nil { 80 log.Infof("Invalid ID during parsing: %s - %v", id, err) 81 return fmt.Errorf("Invalid ID during parsing: %s - %w", id, err) 82 } 83 84 log.Infof("Got eventID %d", eventID) 85 86 attr := unix.PerfEventAttr{ 87 Type: unix.PERF_TYPE_TRACEPOINT, 88 Sample: 1, 89 Wakeup: 1, 90 Config: uint64(eventID), 91 } 92 attr.Size = uint32(unsafe.Sizeof(attr)) 93 94 fd, err := unix.PerfEventOpen(&attr, -1, 0, -1, unix.PERF_FLAG_FD_CLOEXEC) 95 if err != nil { 96 log.Infof("Failed to open perf event %v", err) 97 return fmt.Errorf("Failed to open perf event %v", err) 98 } 99 //defer unix.Close(fd) 100 101 log.Infof("Attach bpf program to perf event Prog FD %d Event FD %d", progFD, fd) 102 103 if _, _, err := unix.Syscall(unix.SYS_IOCTL, uintptr(int(fd)), uintptr(uint(unix.PERF_EVENT_IOC_SET_BPF)), uintptr(progFD)); err != 0 { 104 log.Infof("error attaching bpf program to perf event: %v", err) 105 return fmt.Errorf("error attaching bpf program to perf event: %v", err) 106 } 107 108 if _, _, err := unix.Syscall(unix.SYS_IOCTL, uintptr(int(fd)), uintptr(uint(unix.PERF_EVENT_IOC_ENABLE)), 0); err != 0 { 109 log.Infof("error enabling perf event: %v", err) 110 return fmt.Errorf("error enabling perf event: %v", err) 111 } 112 113 log.Infof("Attach done!!! %d", fd) 114 return nil 115 116 } 117 118 /* 119 p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS] : Set a probe 120 r[MAXACTIVE][:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS] : Set a return probe 121 -:[GRP/]EVENT 122 123 MAXACTIVE : Maximum number of instances of the specified function that 124 can be probed simultaneously, or 0 for the default value 125 as defined in Documentation/kprobes.txt section 1.3.1. 126 127 */ 128 129 // if event is nil, we pick funcName 130 func KretprobeAttach(progFD int, eventName string, funcName string) error { 131 132 //var log = logger.Get() 133 134 if progFD <= 0 { 135 log.Infof("Invalid BPF prog FD %d", progFD) 136 return fmt.Errorf("Invalid BPF prog FD %d", progFD) 137 138 } 139 140 if len(eventName) == 0 { 141 eventName = funcName 142 } 143 144 // Register the Kprobe event 145 file, err := os.OpenFile(kprobeSysEventsFile, os.O_WRONLY|os.O_APPEND, 0) 146 if err != nil { 147 log.Infof("error opening kprobe_events file: %v", err) 148 return fmt.Errorf("error opening kprobe_events file: %v", err) 149 } 150 //defer file.Close() 151 152 eventString := fmt.Sprintf("r4096:kretprobes/%s %s", eventName, funcName) 153 _, err = file.WriteString(eventString) 154 if err != nil { 155 log.Infof("error writing to kprobe_events file: %v", err) 156 return fmt.Errorf("error writing to kprobe_events file: %v", err) 157 } 158 159 //Get the Kprobe ID 160 kprobeIDpath := fmt.Sprintf("/sys/kernel/debug/tracing/events/kretprobes/%s/id", eventName) 161 data, err := os.ReadFile(kprobeIDpath) 162 if err != nil { 163 log.Infof("Unable to read the kretprobeID: %v", err) 164 return fmt.Errorf("Unable to read the kretprobeID: %v", err) 165 } 166 id := strings.TrimSpace(string(data)) 167 eventID, err := strconv.Atoi(id) 168 if err != nil { 169 log.Infof("Invalid ID during parsing: %s - %v", id, err) 170 return fmt.Errorf("Invalid ID during parsing: %s - %w", id, err) 171 } 172 173 log.Infof("Got eventID %d", eventID) 174 175 attr := unix.PerfEventAttr{ 176 Type: unix.PERF_TYPE_TRACEPOINT, 177 Sample: 1, 178 Wakeup: 1, 179 Config: uint64(eventID), 180 } 181 attr.Size = uint32(unsafe.Sizeof(attr)) 182 183 fd, err := unix.PerfEventOpen(&attr, -1, 0, -1, unix.PERF_FLAG_FD_CLOEXEC) 184 if err != nil { 185 log.Infof("Failed to open perf event %v", err) 186 return fmt.Errorf("Failed to open perf event %v", err) 187 } 188 //defer unix.Close(fd) 189 190 log.Infof("Attach bpf program to perf event Prog FD %d Event FD %d", progFD, fd) 191 192 if _, _, err := unix.Syscall(unix.SYS_IOCTL, uintptr(int(fd)), uintptr(uint(unix.PERF_EVENT_IOC_SET_BPF)), uintptr(progFD)); err != 0 { 193 log.Infof("error attaching bpf program to perf event: %v", err) 194 return fmt.Errorf("error attaching bpf program to perf event: %v", err) 195 } 196 197 if _, _, err := unix.Syscall(unix.SYS_IOCTL, uintptr(int(fd)), uintptr(uint(unix.PERF_EVENT_IOC_ENABLE)), 0); err != 0 { 198 log.Infof("error enabling perf event: %v", err) 199 return fmt.Errorf("error enabling perf event: %v", err) 200 } 201 202 log.Infof("Attach done!!! %d", fd) 203 return nil 204 205 } 206 207 func KprobeDetach(eventName string) error { 208 //var log = logger.Get() 209 log.Infof("Calling Detach on %s", eventName) 210 file, err := os.OpenFile(kprobeSysEventsFile, os.O_APPEND|os.O_WRONLY, 0) 211 if err != nil { 212 log.Infof("Cannot open file to detach") 213 return fmt.Errorf("cannot open kprobe events: %v", err) 214 } 215 defer file.Close() 216 217 eventString := fmt.Sprintf("-:%s\n", eventName) 218 if _, err = file.WriteString(eventString); err != nil { 219 pathErr, ok := err.(*os.PathError) 220 if ok && pathErr.Err == syscall.ENOENT { 221 log.Infof("File is already cleanedup, maybe some other process?") 222 return nil 223 } 224 log.Infof("Cannot update the kprobe events %v", err) 225 return fmt.Errorf("cannot update the kprobe_events: %v", err) 226 } 227 log.Infof("Detach done!!!") 228 return nil 229 }