github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/gadgets/audit/seccomp/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/audit/seccomp/types"
    32  	eventtypes "github.com/inspektor-gadget/inspektor-gadget/pkg/types"
    33  )
    34  
    35  //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target $TARGET -type event -cc clang -cflags ${CFLAGS} auditseccomp ./bpf/audit-seccomp.bpf.c -- -I./bpf/ -D__KERNEL__
    36  
    37  type Tracer struct {
    38  	config        *Config
    39  	enricher      gadgets.DataEnricherByMntNs
    40  	eventCallback func(*types.Event)
    41  
    42  	objs   auditseccompObjects
    43  	reader *perf.Reader
    44  
    45  	// progLink links the BPF program to the tracepoint.
    46  	// A reference is kept so it can be closed it explicitly, otherwise
    47  	// the garbage collector might unlink it via the finalizer at any
    48  	// moment.
    49  	progLink link.Link
    50  }
    51  
    52  type Config struct {
    53  	MountnsMap *ebpf.Map
    54  }
    55  
    56  func NewTracer(config *Config, enricher gadgets.DataEnricherByMntNs,
    57  	eventCallback func(*types.Event),
    58  ) (*Tracer, error) {
    59  	t := &Tracer{
    60  		config:        config,
    61  		enricher:      enricher,
    62  		eventCallback: eventCallback,
    63  	}
    64  
    65  	if err := t.install(); err != nil {
    66  		t.Close()
    67  		return nil, err
    68  	}
    69  
    70  	go t.run()
    71  
    72  	return t, nil
    73  }
    74  
    75  func (t *Tracer) install() error {
    76  	spec, err := loadAuditseccomp()
    77  	if err != nil {
    78  		return fmt.Errorf("loading ebpf program: %w", err)
    79  	}
    80  
    81  	if err := gadgets.LoadeBPFSpec(t.config.MountnsMap, spec, nil, &t.objs); err != nil {
    82  		return fmt.Errorf("loading ebpf spec: %w", err)
    83  	}
    84  
    85  	t.reader, err = perf.NewReader(t.objs.Events, gadgets.PerfBufferPages*os.Getpagesize())
    86  	if err != nil {
    87  		return fmt.Errorf("getting a perf reader: %w", err)
    88  	}
    89  
    90  	t.progLink, err = link.Kprobe("audit_seccomp", t.objs.IgAuditSecc, nil)
    91  	if err != nil {
    92  		return fmt.Errorf("attaching kprobe: %w", err)
    93  	}
    94  
    95  	return nil
    96  }
    97  
    98  func (t *Tracer) run() {
    99  	for {
   100  		record, err := t.reader.Read()
   101  		if err != nil {
   102  			if errors.Is(err, perf.ErrClosed) {
   103  				// nothing to do, we're done
   104  				return
   105  			}
   106  
   107  			msg := fmt.Sprintf("Error reading perf ring buffer: %s", err)
   108  			t.eventCallback(types.Base(eventtypes.Err(msg)))
   109  			return
   110  		}
   111  
   112  		if record.LostSamples > 0 {
   113  			msg := fmt.Sprintf("lost %d samples", record.LostSamples)
   114  			t.eventCallback(types.Base(eventtypes.Warn(msg)))
   115  			continue
   116  		}
   117  
   118  		eventC := (*auditseccompEvent)(unsafe.Pointer(&record.RawSample[0]))
   119  
   120  		event := types.Event{
   121  			Event: eventtypes.Event{
   122  				Type:      eventtypes.NORMAL,
   123  				Timestamp: gadgets.WallTimeFromBootTime(eventC.Timestamp),
   124  			},
   125  			Pid:           uint32(eventC.Pid),
   126  			WithMountNsID: eventtypes.WithMountNsID{MountNsID: eventC.MntnsId},
   127  			Syscall:       syscallToName(int(eventC.Syscall)),
   128  			Code:          codeToName(uint(eventC.Code)),
   129  			Comm:          gadgets.FromCString(eventC.Comm[:]),
   130  		}
   131  
   132  		if t.enricher != nil {
   133  			t.enricher.EnrichByMntNs(&event.CommonData, event.MountNsID)
   134  		}
   135  
   136  		t.eventCallback(&event)
   137  	}
   138  }
   139  
   140  // Close closes the tracer
   141  // TODO: Unexport this function when the refactoring is done
   142  func (t *Tracer) Close() {
   143  	t.progLink = gadgets.CloseLink(t.progLink)
   144  	if t.reader != nil {
   145  		t.reader.Close()
   146  	}
   147  	t.objs.Close()
   148  }
   149  
   150  // ---
   151  
   152  func (t *Tracer) Run(gadgetCtx gadgets.GadgetContext) error {
   153  	defer t.Close()
   154  	if err := t.install(); err != nil {
   155  		return fmt.Errorf("installing tracer: %w", err)
   156  	}
   157  
   158  	go t.run()
   159  	gadgetcontext.WaitForTimeoutOrDone(gadgetCtx)
   160  
   161  	return nil
   162  }
   163  
   164  func (t *Tracer) SetMountNsMap(mountnsMap *ebpf.Map) {
   165  	t.config.MountnsMap = mountnsMap
   166  }
   167  
   168  func (t *Tracer) SetEventHandler(handler any) {
   169  	nh, ok := handler.(func(ev *types.Event))
   170  	if !ok {
   171  		panic("event handler invalid")
   172  	}
   173  	t.eventCallback = nh
   174  }
   175  
   176  func (g *GadgetDesc) NewInstance() (gadgets.Gadget, error) {
   177  	t := &Tracer{
   178  		config: &Config{},
   179  	}
   180  	return t, nil
   181  }