github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/gadgets/trace/mount/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 29 gadgetcontext "github.com/inspektor-gadget/inspektor-gadget/pkg/gadget-context" 30 "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets" 31 "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/mount/types" 32 eventtypes "github.com/inspektor-gadget/inspektor-gadget/pkg/types" 33 ) 34 35 //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -no-global-types -target bpfel -cc clang -cflags ${CFLAGS} -type event -type op mountsnoop ./bpf/mountsnoop.bpf.c -- -I./bpf/ 36 37 type Config struct { 38 MountnsMap *ebpf.Map 39 } 40 41 type Tracer struct { 42 config *Config 43 enricher gadgets.DataEnricherByMntNs 44 eventCallback func(*types.Event) 45 46 objs mountsnoopObjects 47 mountEnterLink link.Link 48 umountEnterLink link.Link 49 mountExitLink link.Link 50 umountExitLink link.Link 51 reader *perf.Reader 52 } 53 54 func NewTracer(config *Config, enricher gadgets.DataEnricherByMntNs, 55 eventCallback func(*types.Event), 56 ) (*Tracer, error) { 57 t := &Tracer{ 58 config: config, 59 enricher: enricher, 60 eventCallback: eventCallback, 61 } 62 63 if err := t.install(); err != nil { 64 t.close() 65 return nil, err 66 } 67 68 go t.run() 69 70 return t, nil 71 } 72 73 // Stop stops the tracer 74 // TODO: Remove after refactoring 75 func (t *Tracer) Stop() { 76 t.close() 77 } 78 79 func (t *Tracer) close() { 80 t.mountEnterLink = gadgets.CloseLink(t.mountEnterLink) 81 t.umountEnterLink = gadgets.CloseLink(t.umountEnterLink) 82 t.mountExitLink = gadgets.CloseLink(t.mountExitLink) 83 t.umountExitLink = gadgets.CloseLink(t.umountExitLink) 84 85 if t.reader != nil { 86 t.reader.Close() 87 } 88 89 t.objs.Close() 90 } 91 92 func (t *Tracer) install() error { 93 var err error 94 spec, err := loadMountsnoop() 95 if err != nil { 96 return fmt.Errorf("loading ebpf program: %w", err) 97 } 98 99 if err := gadgets.LoadeBPFSpec(t.config.MountnsMap, spec, nil, &t.objs); err != nil { 100 return fmt.Errorf("loading ebpf spec: %w", err) 101 } 102 103 t.mountEnterLink, err = link.Tracepoint("syscalls", "sys_enter_mount", t.objs.IgMountE, nil) 104 if err != nil { 105 return fmt.Errorf("attaching tracepoint: %w", err) 106 } 107 108 t.mountExitLink, err = link.Tracepoint("syscalls", "sys_exit_mount", t.objs.IgMountX, nil) 109 if err != nil { 110 return fmt.Errorf("attaching tracepoint: %w", err) 111 } 112 113 t.umountEnterLink, err = link.Tracepoint("syscalls", "sys_enter_umount", t.objs.IgUmountE, nil) 114 if err != nil { 115 return fmt.Errorf("attaching tracepoint: %w", err) 116 } 117 118 t.umountExitLink, err = link.Tracepoint("syscalls", "sys_exit_umount", t.objs.IgUmountX, nil) 119 if err != nil { 120 return fmt.Errorf("attaching tracepoint: %w", err) 121 } 122 123 t.reader, err = perf.NewReader(t.objs.mountsnoopMaps.Events, gadgets.PerfBufferPages*os.Getpagesize()) 124 if err != nil { 125 return fmt.Errorf("creating perf ring buffer: %w", err) 126 } 127 128 return nil 129 } 130 131 func (t *Tracer) run() { 132 for { 133 record, err := t.reader.Read() 134 if err != nil { 135 if errors.Is(err, perf.ErrClosed) { 136 // nothing to do, we're done 137 return 138 } 139 140 msg := fmt.Sprintf("Error reading perf ring buffer: %s", err) 141 t.eventCallback(types.Base(eventtypes.Err(msg))) 142 return 143 } 144 145 if record.LostSamples > 0 { 146 msg := fmt.Sprintf("lost %d samples", record.LostSamples) 147 t.eventCallback(types.Base(eventtypes.Warn(msg))) 148 continue 149 } 150 151 bpfEvent := (*mountsnoopEvent)(unsafe.Pointer(&record.RawSample[0])) 152 153 event := types.Event{ 154 Event: eventtypes.Event{ 155 Type: eventtypes.NORMAL, 156 Timestamp: gadgets.WallTimeFromBootTime(bpfEvent.Timestamp), 157 }, 158 WithMountNsID: eventtypes.WithMountNsID{MountNsID: bpfEvent.MountNsId}, 159 Pid: bpfEvent.Pid, 160 Tid: bpfEvent.Tid, 161 Comm: gadgets.FromCString(bpfEvent.Comm[:]), 162 Retval: int(bpfEvent.Ret), 163 Latency: bpfEvent.Delta, 164 Fs: gadgets.FromCString(bpfEvent.Fs[:]), 165 Source: gadgets.FromCString(bpfEvent.Src[:]), 166 Target: gadgets.FromCString(bpfEvent.Dest[:]), 167 Data: gadgets.FromCString(bpfEvent.Data[:]), 168 } 169 170 switch bpfEvent.Op { 171 case mountsnoopOpMOUNT: 172 event.Operation = "mount" 173 case mountsnoopOpUMOUNT: 174 event.Operation = "umount" 175 default: 176 event.Operation = "unknown" 177 } 178 179 event.Flags = DecodeFlags(bpfEvent.Flags) 180 181 if t.enricher != nil { 182 t.enricher.EnrichByMntNs(&event.CommonData, event.MountNsID) 183 } 184 185 t.eventCallback(&event) 186 } 187 } 188 189 // --- Registry changes 190 191 func (t *Tracer) Run(gadgetCtx gadgets.GadgetContext) error { 192 defer t.close() 193 if err := t.install(); err != nil { 194 return fmt.Errorf("installing tracer: %w", err) 195 } 196 197 go t.run() 198 gadgetcontext.WaitForTimeoutOrDone(gadgetCtx) 199 200 return nil 201 } 202 203 func (t *Tracer) SetMountNsMap(mountnsMap *ebpf.Map) { 204 t.config.MountnsMap = mountnsMap 205 } 206 207 func (t *Tracer) SetEventHandler(handler any) { 208 nh, ok := handler.(func(ev *types.Event)) 209 if !ok { 210 panic("event handler invalid") 211 } 212 t.eventCallback = nh 213 } 214 215 func (g *GadgetDesc) NewInstance() (gadgets.Gadget, error) { 216 tracer := &Tracer{ 217 config: &Config{}, 218 } 219 return tracer, nil 220 }