github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/gadgets/trace/capabilities/tracer/tracer.go (about) 1 // Copyright 2019-2023 The Inspektor Gadget authors 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 //go:build !withoutebpf 16 17 package tracer 18 19 import ( 20 "errors" 21 "fmt" 22 "os" 23 "unsafe" 24 25 "github.com/cilium/ebpf" 26 "github.com/cilium/ebpf/link" 27 "github.com/cilium/ebpf/perf" 28 "github.com/syndtr/gocapability/capability" 29 30 gadgetcontext "github.com/inspektor-gadget/inspektor-gadget/pkg/gadget-context" 31 "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets" 32 "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/capabilities/types" 33 eventtypes "github.com/inspektor-gadget/inspektor-gadget/pkg/types" 34 "github.com/inspektor-gadget/inspektor-gadget/pkg/utils/syscalls" 35 ) 36 37 //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target ${TARGET} -cc clang -cflags ${CFLAGS} -type cap_event capabilities ./bpf/capable.bpf.c -- -I./bpf/ 38 39 type Config struct { 40 MountnsMap *ebpf.Map 41 AuditOnly bool 42 Unique bool 43 } 44 45 type Tracer struct { 46 config *Config 47 objs capabilitiesObjects 48 capEnterLink link.Link 49 capExitLink link.Link 50 tpSysEnter link.Link 51 tpSysExit link.Link 52 reader *perf.Reader 53 enricher gadgets.DataEnricherByMntNs 54 eventCallback func(*types.Event) 55 } 56 57 var capabilitiesNames = map[int32]string{ 58 0: "CHOWN", 59 1: "DAC_OVERRIDE", 60 2: "DAC_READ_SEARCH", 61 3: "FOWNER", 62 4: "FSETID", 63 5: "KILL", 64 6: "SETGID", 65 7: "SETUID", 66 8: "SETPCAP", 67 9: "LINUX_IMMUTABLE", 68 10: "NET_BIND_SERVICE", 69 11: "NET_BROADCAST", 70 12: "NET_ADMIN", 71 13: "NET_RAW", 72 14: "IPC_LOCK", 73 15: "IPC_OWNER", 74 16: "SYS_MODULE", 75 17: "SYS_RAWIO", 76 18: "SYS_CHROOT", 77 19: "SYS_PTRACE", 78 20: "SYS_PACCT", 79 21: "SYS_ADMIN", 80 22: "SYS_BOOT", 81 23: "SYS_NICE", 82 24: "SYS_RESOURCE", 83 25: "SYS_TIME", 84 26: "SYS_TTY_CONFIG", 85 27: "MKNOD", 86 28: "LEASE", 87 29: "AUDIT_WRITE", 88 30: "AUDIT_CONTROL", 89 31: "SETFCAP", 90 32: "MAC_OVERRIDE", 91 33: "MAC_ADMIN", 92 34: "SYSLOG", 93 35: "WAKE_ALARM", 94 36: "BLOCK_SUSPEND", 95 37: "AUDIT_READ", 96 38: "PERFMON", 97 39: "BPF", 98 40: "CHECKPOINT_RESTORE", 99 } 100 101 func NewTracer(c *Config, enricher gadgets.DataEnricherByMntNs, 102 eventCallback func(*types.Event), 103 ) (*Tracer, error) { 104 t := &Tracer{ 105 config: c, 106 enricher: enricher, 107 eventCallback: eventCallback, 108 } 109 110 if err := t.install(); err != nil { 111 t.close() 112 return nil, err 113 } 114 115 go t.run() 116 117 return t, nil 118 } 119 120 // Stop stops the tracer 121 // TODO: Remove after refactoring 122 func (t *Tracer) Stop() { 123 t.close() 124 } 125 126 func (t *Tracer) close() { 127 t.capEnterLink = gadgets.CloseLink(t.capEnterLink) 128 t.capExitLink = gadgets.CloseLink(t.capExitLink) 129 t.tpSysEnter = gadgets.CloseLink(t.tpSysEnter) 130 t.tpSysExit = gadgets.CloseLink(t.tpSysExit) 131 132 if t.reader != nil { 133 t.reader.Close() 134 } 135 136 t.objs.Close() 137 } 138 139 func (t *Tracer) install() error { 140 spec, err := loadCapabilities() 141 if err != nil { 142 return fmt.Errorf("loading ebpf program: %w", err) 143 } 144 145 consts := map[string]interface{}{ 146 "audit_only": t.config.AuditOnly, 147 "unique": t.config.Unique, 148 } 149 150 if err := gadgets.LoadeBPFSpec(t.config.MountnsMap, spec, consts, &t.objs); err != nil { 151 return fmt.Errorf("loading ebpf spec: %w", err) 152 } 153 154 tp, err := link.AttachRawTracepoint(link.RawTracepointOptions{ 155 Name: "sys_enter", 156 Program: t.objs.IgCapSysEnter, 157 }) 158 if err != nil { 159 return fmt.Errorf("attaching tracepoint: %w", err) 160 } 161 t.tpSysEnter = tp 162 163 tp, err = link.AttachRawTracepoint(link.RawTracepointOptions{ 164 Name: "sys_exit", 165 Program: t.objs.IgCapSysExit, 166 }) 167 if err != nil { 168 return fmt.Errorf("attaching tracepoint: %w", err) 169 } 170 t.tpSysEnter = tp 171 172 kprobe, err := link.Kprobe("cap_capable", t.objs.IgTraceCapE, nil) 173 if err != nil { 174 return fmt.Errorf("attaching kprobe: %w", err) 175 } 176 t.capEnterLink = kprobe 177 178 kretprobe, err := link.Kretprobe("cap_capable", t.objs.IgTraceCapX, nil) 179 if err != nil { 180 return fmt.Errorf("attaching kretprobe: %w", err) 181 } 182 t.capExitLink = kretprobe 183 184 reader, err := perf.NewReader(t.objs.capabilitiesMaps.Events, gadgets.PerfBufferPages*os.Getpagesize()) 185 if err != nil { 186 return fmt.Errorf("creating perf ring buffer: %w", err) 187 } 188 t.reader = reader 189 190 return nil 191 } 192 193 func capsNames(capsBitField uint64) (ret []string) { 194 // Ensure ret is not nil 195 ret = []string{} 196 for i := capability.Cap(0); i <= capability.CAP_LAST_CAP; i++ { 197 if (1<<uint(i))&capsBitField != 0 { 198 ret = append(ret, i.String()) 199 } 200 } 201 return 202 } 203 204 func boolPointer(b bool) *bool { 205 return &b 206 } 207 208 func (t *Tracer) run() { 209 for { 210 record, err := t.reader.Read() 211 if err != nil { 212 if errors.Is(err, perf.ErrClosed) { 213 // nothing to do, we're done 214 return 215 } 216 217 msg := fmt.Sprintf("Error reading perf ring buffer: %s", err) 218 t.eventCallback(types.Base(eventtypes.Err(msg))) 219 return 220 } 221 222 if record.LostSamples > 0 { 223 msg := fmt.Sprintf("lost %d samples", record.LostSamples) 224 t.eventCallback(types.Base(eventtypes.Warn(msg))) 225 continue 226 } 227 228 if len(record.RawSample) < 1 { 229 t.eventCallback(types.Base(eventtypes.Warn("empty record"))) 230 continue 231 } 232 233 bpfEvent := (*capabilitiesCapEvent)(unsafe.Pointer(&record.RawSample[0])) 234 235 capability := bpfEvent.Cap 236 capabilityName, ok := capabilitiesNames[capability] 237 if !ok { 238 // If this is printed it may mean a new capability was added to the kernel 239 // and capabilitiesNames map needs to be updated. 240 capabilityName = fmt.Sprintf("UNKNOWN (%d)", capability) 241 } 242 243 verdict := "Deny" 244 if bpfEvent.Ret == 0 { 245 verdict = "Allow" 246 } 247 248 syscall, ok := syscalls.GetSyscallNameByNumber(int(bpfEvent.Syscall)) 249 if !ok { 250 syscall = fmt.Sprintf("syscall%d", int(bpfEvent.Syscall)) 251 } 252 253 var insetID *bool 254 if bpfEvent.Insetid == 0 { 255 insetID = boolPointer(false) 256 } else if bpfEvent.Insetid > 0 { 257 insetID = boolPointer(true) 258 } 259 260 event := types.Event{ 261 Event: eventtypes.Event{ 262 Type: eventtypes.NORMAL, 263 Timestamp: gadgets.WallTimeFromBootTime(bpfEvent.Timestamp), 264 }, 265 WithMountNsID: eventtypes.WithMountNsID{MountNsID: bpfEvent.Mntnsid}, 266 TargetUserNs: bpfEvent.TargetUserns, 267 CurrentUserNs: bpfEvent.CurrentUserns, 268 Pid: bpfEvent.Pid, 269 Cap: int(bpfEvent.Cap), 270 Uid: bpfEvent.Uid, 271 Gid: bpfEvent.Gid, 272 Audit: int(bpfEvent.Audit), 273 InsetID: insetID, 274 Comm: gadgets.FromCString(bpfEvent.Task[:]), 275 Syscall: syscall, 276 CapName: capabilityName, 277 Verdict: verdict, 278 Caps: bpfEvent.CapEffective, 279 CapsNames: capsNames(bpfEvent.CapEffective), 280 } 281 282 if t.enricher != nil { 283 t.enricher.EnrichByMntNs(&event.CommonData, event.MountNsID) 284 } 285 286 t.eventCallback(&event) 287 } 288 } 289 290 // --- Registry changes 291 292 func (t *Tracer) Run(gadgetCtx gadgets.GadgetContext) error { 293 params := gadgetCtx.GadgetParams() 294 t.config.Unique = params.Get(ParamUnique).AsBool() 295 t.config.AuditOnly = params.Get(ParamAuditOnly).AsBool() 296 297 defer t.close() 298 if err := t.install(); err != nil { 299 return fmt.Errorf("installing tracer: %w", err) 300 } 301 302 go t.run() 303 gadgetcontext.WaitForTimeoutOrDone(gadgetCtx) 304 305 return nil 306 } 307 308 func (t *Tracer) SetMountNsMap(mountnsMap *ebpf.Map) { 309 t.config.MountnsMap = mountnsMap 310 } 311 312 func (t *Tracer) SetEventHandler(handler any) { 313 nh, ok := handler.(func(ev *types.Event)) 314 if !ok { 315 panic("event handler invalid") 316 } 317 t.eventCallback = nh 318 } 319 320 func (g *GadgetDesc) NewInstance() (gadgets.Gadget, error) { 321 tracer := &Tracer{ 322 config: &Config{}, 323 } 324 return tracer, nil 325 }