diff --git a/pkg/ebpf/tracee.go b/pkg/ebpf/tracee.go index 690e4cbbff67..7165d45b0bf1 100644 --- a/pkg/ebpf/tracee.go +++ b/pkg/ebpf/tracee.go @@ -507,33 +507,50 @@ func (t *Tracee) generateInitValues() (InitValues, error) { // initTailCall initializes a given tailcall. func (t *Tracee) initTailCall(tailCall events.TailCall) error { - bpfMap, err := t.bpfModule.GetMap(tailCall.GetMapName()) + tailCallMapName := tailCall.GetMapName() + tailCallProgName := tailCall.GetProgName() + tailCallIndexes := tailCall.GetIndexes() + + // Pick eBPF map by name. + bpfMap, err := t.bpfModule.GetMap(tailCallMapName) if err != nil { return errfmt.WrapError(err) } - progName := tailCall.GetProgName() - bpfProg, err := t.bpfModule.GetProgram(progName) + // Pick eBPF program by name. + bpfProg, err := t.bpfModule.GetProgram(tailCallProgName) if err != nil { - return errfmt.Errorf("could not get BPF program %s: %v", progName, err) + return errfmt.Errorf("could not get BPF program %s: %v", tailCallProgName, err) } - fd := bpfProg.FileDescriptor() - if fd < 0 { - return errfmt.Errorf("could not get BPF program FD for %s: %v", progName, err) + // Pick eBPF program file descriptor. + bpfProgFD := bpfProg.FileDescriptor() + if bpfProgFD < 0 { + return errfmt.Errorf("could not get BPF program FD for %s: %v", tailCallProgName, err) } - // Attach internal syscall probes if needed. - for _, index := range tailCall.GetIndexes() { + once := &sync.Once{} + + // Pick all indexes (event, or syscall, IDs) the BPF program should be related to. + for _, index := range tailCallIndexes { + // Special treatment for indexes of syscall events. if events.Core.GetDefinitionByID(events.ID(index)).IsSyscall() { - err := t.probes.Attach(probes.SyscallEnter__Internal) - if err != nil { - return errfmt.WrapError(err) - } - err = t.probes.Attach(probes.SyscallExit__Internal) - if err != nil { - return errfmt.WrapError(err) + // Optimization: enable enter/exit probes only if at least one syscall is enabled. + once.Do(func() { + err := t.probes.Attach(probes.SyscallEnter__Internal) + if err != nil { + logger.Errorw("error attaching to syscall enter", "error", err) + } + err = t.probes.Attach(probes.SyscallExit__Internal) + if err != nil { + logger.Errorw("error attaching to syscall enter", "error", err) + } + }) + // Workaround: Do not map eBPF program to unsupported syscalls (arm64, e.g.) + if index >= uint32(events.Unsupported) { + continue } } - err := bpfMap.Update(unsafe.Pointer(&index), unsafe.Pointer(&fd)) + // Update given eBPF map with the eBPF program file descriptor at given index. + err := bpfMap.Update(unsafe.Pointer(&index), unsafe.Pointer(&bpfProgFD)) if err != nil { return errfmt.WrapError(err) } diff --git a/pkg/events/core.go b/pkg/events/core.go index 03bb2fb45be7..58d0ec3ba384 100644 --- a/pkg/events/core.go +++ b/pkg/events/core.go @@ -12,6 +12,7 @@ import ( const ( Sys32Undefined ID = 0xfffffff - 1 // u32 overflows are compiler implementation dependent. Undefined ID = 0xfffffff + Unsupported ID = 10000 ) type ID int32 diff --git a/pkg/events/core_arm64.go b/pkg/events/core_arm64.go index 97dadd0963c0..290d47c03bed 100644 --- a/pkg/events/core_arm64.go +++ b/pkg/events/core_arm64.go @@ -353,7 +353,7 @@ const ( // following syscalls are undefined on arm64 const ( - Open ID = iota + 10000 + Open ID = iota + Unsupported Stat Lstat Poll @@ -954,7 +954,7 @@ const ( // following syscalls are undefined on arm32 const ( - Sys32arch_prctl ID = iota + 10000 + Sys32arch_prctl ID = iota + Unsupported Sys32getpmsg Sys32putpmsg Sys32set_thread_area diff --git a/pkg/events/definition_group.go b/pkg/events/definition_group.go index 5a58715059bc..07bc126de381 100644 --- a/pkg/events/definition_group.go +++ b/pkg/events/definition_group.go @@ -43,12 +43,12 @@ func NewDefinitionGroup() *DefinitionGroup { // GetDefinitions returns a new map of existing definitions. // TODO: iterate internally after event definition refactor is finished ? -func (e *DefinitionGroup) GetDefinitions() []Definition { - e.mutex.RLock() - defer e.mutex.RUnlock() +func (d *DefinitionGroup) GetDefinitions() []Definition { + d.mutex.RLock() + defer d.mutex.RUnlock() - definitions := make([]Definition, 0, len(e.definitions)) - for _, def := range e.definitions { + definitions := make([]Definition, 0, len(d.definitions)) + for _, def := range d.definitions { definitions = append(definitions, def) } sort.Sort(ByID(definitions)) @@ -57,15 +57,15 @@ func (e *DefinitionGroup) GetDefinitions() []Definition { } // GetDefinitionIDByName returns a definition ID by its name. -func (e *DefinitionGroup) GetDefinitionIDByName(givenName string) (ID, bool) { - e.mutex.RLock() - defer e.mutex.RUnlock() - return e.getDefinitionIDByName(givenName) +func (d *DefinitionGroup) GetDefinitionIDByName(givenName string) (ID, bool) { + d.mutex.RLock() + defer d.mutex.RUnlock() + return d.getDefinitionIDByName(givenName) } // getDefinitionIDByName returns a definition ID by its name (no locking). -func (e *DefinitionGroup) getDefinitionIDByName(givenName string) (ID, bool) { - for id, def := range e.definitions { +func (d *DefinitionGroup) getDefinitionIDByName(givenName string) (ID, bool) { + for id, def := range d.definitions { if def.GetName() == givenName { return id, true } @@ -77,11 +77,11 @@ func (e *DefinitionGroup) getDefinitionIDByName(givenName string) (ID, bool) { // GetDefinitionByID returns a definition by its ID. // NOTE: should be used together with IsDefined when definition might not exist. -func (e *DefinitionGroup) GetDefinitionByID(givenDef ID) Definition { - e.mutex.RLock() - defer e.mutex.RUnlock() +func (d *DefinitionGroup) GetDefinitionByID(givenDef ID) Definition { + d.mutex.RLock() + defer d.mutex.RUnlock() - def, ok := e.definitions[givenDef] + def, ok := d.definitions[givenDef] if !ok { logger.Debugw("definition id not found", "id", givenDef) return Definition{id: Undefined} @@ -92,35 +92,35 @@ func (e *DefinitionGroup) GetDefinitionByID(givenDef ID) Definition { // IsDefined returns true if the definition exists in the definition group. // NOTE: needed as GetDefinitionByID() is used as GetDefinitionByID().Method() multiple times. -func (e *DefinitionGroup) IsDefined(givenDef ID) bool { - e.mutex.RLock() - defer e.mutex.RUnlock() +func (d *DefinitionGroup) IsDefined(givenDef ID) bool { + d.mutex.RLock() + defer d.mutex.RUnlock() - _, ok := e.definitions[givenDef] + _, ok := d.definitions[givenDef] return ok } // Length returns the number of definitions in the definition group. -func (e *DefinitionGroup) Length() int { - e.mutex.RLock() - defer e.mutex.RUnlock() - return len(e.definitions) +func (d *DefinitionGroup) Length() int { + d.mutex.RLock() + defer d.mutex.RUnlock() + return len(d.definitions) } // Add adds a definition to the definition group. -func (e *DefinitionGroup) Add(givenId ID, givenDef Definition) error { - e.mutex.Lock() - defer e.mutex.Unlock() - return e.add(givenId, givenDef) +func (d *DefinitionGroup) Add(givenId ID, givenDef Definition) error { + d.mutex.Lock() + defer d.mutex.Unlock() + return d.add(givenId, givenDef) } // AddBatch adds multiple definitions to the definition group. -func (e *DefinitionGroup) AddBatch(givenDefs map[ID]Definition) error { - e.mutex.Lock() - defer e.mutex.Unlock() +func (d *DefinitionGroup) AddBatch(givenDefs map[ID]Definition) error { + d.mutex.Lock() + defer d.mutex.Unlock() for id, def := range givenDefs { - err := e.add(id, def) + err := d.add(id, def) if err != nil { return err } @@ -130,29 +130,29 @@ func (e *DefinitionGroup) AddBatch(givenDefs map[ID]Definition) error { } // add adds a definition to the definition group (no locking). -func (e *DefinitionGroup) add(givenId ID, givenDef Definition) error { - if _, ok := e.definitions[givenId]; ok { +func (d *DefinitionGroup) add(givenId ID, givenDef Definition) error { + if _, ok := d.definitions[givenId]; ok { return definitionIDAlreadyExistsErr(givenId) } n := givenDef.GetName() - if _, ok := e.getDefinitionIDByName(n); ok { + if _, ok := d.getDefinitionIDByName(n); ok { return definitionNameAlreadyExistsErr(n) } - e.definitions[givenId] = givenDef + d.definitions[givenId] = givenDef return nil } // NamesToIDs returns a new map of definition names to their IDs. -func (e *DefinitionGroup) NamesToIDs() map[string]ID { - e.mutex.RLock() - defer e.mutex.RUnlock() +func (d *DefinitionGroup) NamesToIDs() map[string]ID { + d.mutex.RLock() + defer d.mutex.RUnlock() - namesToIds := make(map[string]ID, len(e.definitions)) + namesToIds := make(map[string]ID, len(d.definitions)) - for id, def := range e.definitions { + for id, def := range d.definitions { namesToIds[def.GetName()] = id } @@ -160,13 +160,13 @@ func (e *DefinitionGroup) NamesToIDs() map[string]ID { } // IDs32ToIDs returns a new map of 32-bit definition IDs to their IDs. -func (e *DefinitionGroup) IDs32ToIDs() map[ID]ID { - e.mutex.RLock() - defer e.mutex.RUnlock() +func (d *DefinitionGroup) IDs32ToIDs() map[ID]ID { + d.mutex.RLock() + defer d.mutex.RUnlock() - idS32ToIDs := make(map[ID]ID, len(e.definitions)) + idS32ToIDs := make(map[ID]ID, len(d.definitions)) - for id, def := range e.definitions { + for id, def := range d.definitions { id32Bit := def.GetID32Bit() if id32Bit != Sys32Undefined { @@ -178,15 +178,15 @@ func (e *DefinitionGroup) IDs32ToIDs() map[ID]ID { } // GetTailCalls returns a list of tailcalls of all definitions in the group (for initialization). -func (e *DefinitionGroup) GetTailCalls(state map[ID]EventState) []TailCall { - e.mutex.RLock() - defer e.mutex.RUnlock() +func (d *DefinitionGroup) GetTailCalls(state map[ID]EventState) []TailCall { + d.mutex.RLock() + defer d.mutex.RUnlock() var tailCalls []TailCall - for id, def := range e.definitions { - if state[id].Submit > 0 { // only traced events to provide their tailcalls - tailCalls = append(tailCalls, def.GetDependencies().GetTailCalls()...) + for evtDefID, evtDef := range d.definitions { + if state[evtDefID].Submit > 0 { // only traced events to provide their tailcalls + tailCalls = append(tailCalls, evtDef.GetDependencies().GetTailCalls()...) } }