diff --git a/pkg/ebpf/ksymbols.go b/pkg/ebpf/ksymbols.go index cfc316ec3a1b..c5a78bca67f1 100644 --- a/pkg/ebpf/ksymbols.go +++ b/pkg/ebpf/ksymbols.go @@ -3,75 +3,68 @@ package ebpf import ( "unsafe" - "github.com/aquasecurity/libbpfgo" - "github.com/aquasecurity/libbpfgo/helpers" - "github.com/aquasecurity/tracee/pkg/errfmt" "github.com/aquasecurity/tracee/pkg/events" + "github.com/aquasecurity/tracee/pkg/logger" ) +// TODO: Just like recent change in `KernelSymbolTable`, in kernel_symbols.go, +// this needs to be changed somehow. Symbols might be duplicated, so might be +// the addresses (https://github.com/aquasecurity/tracee/issues/3798). + var maxKsymNameLen = 64 // Most match the constant in the bpf code var globalSymbolOwner = "system" -func LoadKallsymsValues(ksymsTable *helpers.KernelSymbolTable, ksymbols []string) map[string]helpers.KernelSymbol { - kallsymsMap := make(map[string]helpers.KernelSymbol) - for _, name := range ksymbols { - symbol, err := ksymsTable.GetSymbolByOwnerAndName(globalSymbolOwner, name) - if err == nil { - kallsymsMap[name] = symbol[0] - } +func (t *Tracee) UpdateKallsyms() error { + // NOTE: Make sure to refresh the kernel symbols table before updating the eBPF map. + + // Find the eBPF map. + bpfKsymsMap, err := t.bpfModule.GetMap("ksymbols_map") + if err != nil { + return errfmt.WrapError(err) } - return kallsymsMap -} -func SendKsymbolsToMap(bpfKsymsMap *libbpfgo.BPFMap, ksymbols map[string]helpers.KernelSymbol) error { - for ksymName, value := range ksymbols { - key := make([]byte, maxKsymNameLen) - copy(key, ksymName) - address := value.Address - err := bpfKsymsMap.Update(unsafe.Pointer(&key[0]), unsafe.Pointer(&address)) - if err != nil { - return errfmt.WrapError(err) - } + // Wrap long method names. + evtDefSymDeps := func(id events.ID) []events.KSymbol { + return events.Core.GetDefinitionByID(id).GetDependencies().GetKSymbols() } - return nil -} -func (t *Tracee) UpdateKernelSymbols() error { - return t.kernelSymbols.Refresh() -} + // Get the symbols all events being traced require (t.eventsState already + // includes dependent events, no need to recurse again). -func (t *Tracee) UpdateBPFKsymbolsMap() error { - var err error - var bpfKsymsMap *libbpfgo.BPFMap + var allReqSymbols []string - bpfKsymsMap, err = t.bpfModule.GetMap("ksymbols_map") - if err != nil { - return errfmt.WrapError(err) + for evtID := range t.eventsState { + for _, symDep := range evtDefSymDeps(evtID) { + allReqSymbols = append(allReqSymbols, symDep.GetSymbolName()) + } } - // get required symbols by chosen events - var reqKsyms []string - - for id := range t.eventsState { - if !events.Core.IsDefined(id) { - return errfmt.Errorf("wrong event id: %d", id) - } - eventDependencies := events.Core.GetDefinitionByID(id).GetDependencies() - for _, symDependency := range eventDependencies.GetKSymbols() { - reqKsyms = append(reqKsyms, symDependency.GetSymbol()) + // For every ksymbol required by tracee ... + for _, required := range allReqSymbols { + // ... get the symbol address from the kallsyms file ... + symbol, err := t.kernelSymbols.GetSymbolByOwnerAndName(globalSymbolOwner, required) + if err != nil { + logger.Debugw("failed to get symbol", "symbol", required, "error", err) + continue } - } - kallsymsValues := LoadKallsymsValues(t.kernelSymbols, reqKsyms) - return SendKsymbolsToMap(bpfKsymsMap, kallsymsValues) -} + // ... and update the eBPF map with the symbol address. + for _, sym := range symbol { + key := make([]byte, maxKsymNameLen) + copy(key, sym.Name) + addr := sym.Address -func (t *Tracee) UpdateKallsyms() error { - err := t.UpdateKernelSymbols() - if err != nil { - return errfmt.WrapError(err) + // Update the eBPF map with the symbol address. + err := bpfKsymsMap.Update( + unsafe.Pointer(&key[0]), + unsafe.Pointer(&addr), + ) + if err != nil { + return errfmt.WrapError(err) + } + } // will overwrite the previous value (check TODO) } - return t.UpdateBPFKsymbolsMap() + return nil } diff --git a/pkg/ebpf/processor_funcs.go b/pkg/ebpf/processor_funcs.go index 5541d076b3fc..d857bbbe6eeb 100644 --- a/pkg/ebpf/processor_funcs.go +++ b/pkg/ebpf/processor_funcs.go @@ -213,35 +213,40 @@ func (t *Tracee) processSchedProcessExec(event *trace.Event) error { // processDoFinitModule handles a do_finit_module event and triggers other hooking detection logic. func (t *Tracee) processDoInitModule(event *trace.Event) error { + // Check if related events are being traced. _, okSyscalls := t.eventsState[events.HookedSyscall] _, okSeqOps := t.eventsState[events.HookedSeqOps] _, okProcFops := t.eventsState[events.HookedProcFops] _, okMemDump := t.eventsState[events.PrintMemDump] - if okSyscalls || okSeqOps || okProcFops || okMemDump { - err := capabilities.GetInstance().EBPF( - func() error { - return t.UpdateKallsyms() - }, - ) - if err != nil { - return errfmt.WrapError(err) - } - if err != nil { - return errfmt.WrapError(err) - } - if okSyscalls && expectedSyscallTableInit { - t.triggerSyscallTableIntegrityCheckCall() - } - if okSeqOps { - // Trigger seq_ops hooking detection - t.triggerSeqOpsIntegrityCheck(*event) - } - if okMemDump { - errs := t.triggerMemDump(*event) - for _, err := range errs { - logger.Warnw("Memory dump", "error", err) + if !okSyscalls && !okSeqOps && !okProcFops && !okMemDump { + return nil + } + + err := capabilities.GetInstance().EBPF( + func() error { + err := t.kernelSymbols.Refresh() + if err != nil { + return errfmt.WrapError(err) } + return t.UpdateKallsyms() + }, + ) + if err != nil { + return errfmt.WrapError(err) + } + if okSyscalls && expectedSyscallTableInit { + // Trigger syscall table hooking detection. + t.triggerSyscallTableIntegrityCheckCall() + } + if okSeqOps { + // Trigger seq_ops hooking detection + t.triggerSeqOpsIntegrityCheck(*event) + } + if okMemDump { + errs := t.triggerMemDump(*event) + for _, err := range errs { + logger.Warnw("Memory dump", "error", err) } } diff --git a/pkg/ebpf/tracee.go b/pkg/ebpf/tracee.go index f3768ad396c2..68c348ddb50f 100644 --- a/pkg/ebpf/tracee.go +++ b/pkg/ebpf/tracee.go @@ -964,41 +964,33 @@ func (t *Tracee) computeConfigValues(newPolicies *policy.Policies) []byte { return configVal } -// TODO: move this to Event Definition type, so can be reused by other components -// checkUnavailableKSymbols checks if all kernel symbols required by events are available. -func (t *Tracee) checkUnavailableKSymbols() map[events.ID][]string { - reqKSyms := []string{} +// getUnavKsymsPerEvtID returns event IDs and symbols that are unavailable to them. +func (t *Tracee) getUnavKsymsPerEvtID() map[events.ID][]string { + unavSymsPerEvtID := map[events.ID][]string{} - kSymbolsToEvents := make(map[string][]events.ID) + evtDefSymDeps := func(id events.ID) []events.KSymbol { + return events.Core.GetDefinitionByID(id).GetDependencies().GetKSymbols() + } - // Build a map of kernel symbols to events that require them - for id := range t.eventsState { - evtDefinition := events.Core.GetDefinitionByID(id) - for _, symDep := range evtDefinition.GetDependencies().GetKSymbols() { - if !symDep.IsRequired() { + for evtID := range t.eventsState { + for _, symDep := range evtDefSymDeps(evtID) { + sym, err := t.kernelSymbols.GetSymbolByName(symDep.GetSymbolName()) + symName := symDep.GetSymbolName() + if err != nil { + // If the symbol is not found, it means it's unavailable. + unavSymsPerEvtID[evtID] = append(unavSymsPerEvtID[evtID], symName) continue } - symbol := symDep.GetSymbol() - reqKSyms = append(reqKSyms, symbol) - kSymbolsToEvents[symbol] = append(kSymbolsToEvents[symbol], id) - } - } - - kallsymsValues := LoadKallsymsValues(t.kernelSymbols, reqKSyms) - unavailableKSymsForEventID := make(map[events.ID][]string) - - // Build a map of events that require unavailable kernel symbols - for symName, evtsIDs := range kSymbolsToEvents { - ksym, ok := kallsymsValues[symName] - if ok && ksym.Address != 0 { - continue - } - for _, evtID := range evtsIDs { - unavailableKSymsForEventID[evtID] = append(unavailableKSymsForEventID[evtID], symName) + for _, s := range sym { + if s.Address == 0 { + // Same if the symbol is found but its address is 0. + unavSymsPerEvtID[evtID] = append(unavSymsPerEvtID[evtID], symName) + } + } } } - return unavailableKSymsForEventID + return unavSymsPerEvtID } // validateKallsymsDependencies load all symbols required by events dependencies @@ -1008,7 +1000,7 @@ func (t *Tracee) validateKallsymsDependencies() { depsToCancel := make(map[events.ID]string) // Cancel events with unavailable symbols dependencies - for eventToCancel, missingDepSyms := range t.checkUnavailableKSymbols() { + for eventToCancel, missingDepSyms := range t.getUnavKsymsPerEvtID() { eventNameToCancel := events.Core.GetDefinitionByID(eventToCancel).GetName() logger.Debugw( "Event canceled because of missing kernel symbol dependency", @@ -1053,11 +1045,10 @@ func (t *Tracee) populateBPFMaps() error { } } - if t.kernelSymbols != nil { - err = t.UpdateBPFKsymbolsMap() - if err != nil { - return errfmt.WrapError(err) - } + // Update the kallsyms eBPF map with all symbols from the kallsyms file. + err = t.UpdateKallsyms() + if err != nil { + return errfmt.WrapError(err) } // Initialize kconfig variables (map used instead of relying in libbpf's .kconfig automated maps) @@ -1301,6 +1292,7 @@ func (t *Tracee) initBPF() error { } // Initialize Control Plane + t.controlPlane, err = controlplane.NewController( t.bpfModule, t.containers, diff --git a/pkg/events/definition_dependencies.go b/pkg/events/definition_dependencies.go index faf3b938fa57..4be3186a99e9 100644 --- a/pkg/events/definition_dependencies.go +++ b/pkg/events/definition_dependencies.go @@ -45,6 +45,16 @@ func (d Dependencies) GetKSymbols() []KSymbol { return d.kSymbols } +func (d Dependencies) GetRequiredKSymbols() []KSymbol { + var requiredKSymbols []KSymbol + for _, kSymbol := range d.kSymbols { + if kSymbol.required { + requiredKSymbols = append(requiredKSymbols, kSymbol) + } + } + return requiredKSymbols +} + func (d Dependencies) GetProbes() []Probe { if d.probes == nil { return []Probe{} @@ -85,7 +95,7 @@ type KSymbol struct { required bool // tracee fails if symbol is not found } -func (ks KSymbol) GetSymbol() string { +func (ks KSymbol) GetSymbolName() string { return ks.symbol }