From 735e972fa8d1ba06c2f71f9f0592fdb44e276b65 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 22 Jan 2025 09:20:00 +0000 Subject: [PATCH 1/6] tetragon: Add Maps array to loader LoadOpts object Adding Maps array to loader LoadOpts object as additional source of user maps for loader maps resolving. This will allow program loader to use user maps pinned to another program and will ease up maps sharing for sensors in following changes. At the moment for simplicity we will pass all the sensors maps, so we filter out user maps before using the array. Signed-off-by: Jiri Olsa --- pkg/sensors/program/loader.go | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/pkg/sensors/program/loader.go b/pkg/sensors/program/loader.go index 9afe471c0b8..f396949eca9 100644 --- a/pkg/sensors/program/loader.go +++ b/pkg/sensors/program/loader.go @@ -28,6 +28,7 @@ type OpenFunc func(*ebpf.CollectionSpec) error type LoadOpts struct { Attach AttachFunc Open OpenFunc + Maps []*Map } func linkPinPath(bpfDir string, load *Program, extra ...string) string { @@ -804,8 +805,33 @@ func doLoadProgram( } } + // We have following maps available for loading: + // - maps attached/pinned to program directly in load.PinMap[name] + // - maps passed to loader + // + // We take user maps from loadOpts.Maps and use them to resolve + // program maps in following order: + // 1) load.PinMap[name] + // 2) loadOpts.Maps user maps + + maps := map[string]*Map{} + for _, pm := range loadOpts.Maps { + if !pm.IsOwner() { + maps[pm.Name] = pm + } + } + + getMap := func(name string) (*Map, bool) { + m, ok := load.PinMap[name] + if ok { + return m, true + } + m, ok = maps[name] + return m, ok + } + for _, ms := range spec.Maps { - m, ok := load.PinMap[ms.Name] + m, ok := getMap(ms.Name) if !ok { continue } @@ -847,7 +873,8 @@ func doLoadProgram( var m *ebpf.Map var err error var mapPath string - if pm, ok := load.PinMap[name]; ok { + + if pm, ok := getMap(name); ok { mapPath = filepath.Join(bpfDir, pm.PinPath) } else { mapPath = filepath.Join(bpfDir, name) @@ -950,6 +977,7 @@ func doLoadProgram( for _, mapLoad := range load.MapLoad { pinPath := "" + // We allow to load only maps that we own. if pm, ok := load.PinMap[mapLoad.Name]; ok { pinPath = pm.PinPath } From 63e4a858f6a2ccdcdaadd40ce2fc641d9609c286 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 22 Jan 2025 10:04:05 +0000 Subject: [PATCH 2/6] tetragon: Pass sensor maps to program loader Passing sensors maps to program loader so the loader has access to all sensor maps. Signed-off-by: Jiri Olsa --- pkg/sensors/exec/exec.go | 2 +- pkg/sensors/load.go | 19 +++++++------ pkg/sensors/program/cgroup/cgroup.go | 8 +++--- pkg/sensors/program/loader.go | 36 ++++++++++++++++-------- pkg/sensors/sensors.go | 3 +- pkg/sensors/tracing/enforcer.go | 14 ++++----- pkg/sensors/tracing/generickprobe.go | 16 +++++------ pkg/sensors/tracing/genericlsm.go | 2 +- pkg/sensors/tracing/generictracepoint.go | 6 ++-- pkg/sensors/tracing/genericuprobe.go | 4 +-- pkg/sensors/tracing/loader.go | 2 +- 11 files changed, 63 insertions(+), 49 deletions(-) diff --git a/pkg/sensors/exec/exec.go b/pkg/sensors/exec/exec.go index c9da56c8bb8..693da110106 100644 --- a/pkg/sensors/exec/exec.go +++ b/pkg/sensors/exec/exec.go @@ -261,7 +261,7 @@ func handleThrottleEvent(r *bytes.Reader) ([]observer.Event, error) { type execProbe struct{} func (e *execProbe) LoadProbe(args sensors.LoadProbeArgs) error { - return program.LoadTracepointProgram(args.BPFDir, args.Load, args.Verbose) + return program.LoadTracepointProgram(args.BPFDir, args.Load, args.Maps, args.Verbose) } func init() { diff --git a/pkg/sensors/load.go b/pkg/sensors/load.go index abf3a3b220a..6f796b3e12e 100644 --- a/pkg/sensors/load.go +++ b/pkg/sensors/load.go @@ -170,7 +170,7 @@ func (s *Sensor) Load(bpfDir string) (err error) { continue } - if err = observerLoadInstance(bpfDir, p); err != nil { + if err = observerLoadInstance(bpfDir, p, s.Maps); err != nil { return err } p.LoadState.RefInc() @@ -408,7 +408,7 @@ func mergeSensors(sensors []*Sensor) *Sensor { } } -func observerLoadInstance(bpfDir string, load *program.Program) error { +func observerLoadInstance(bpfDir string, load *program.Program, maps []*program.Map) error { version, _, err := kernels.GetKernelVersion(option.Config.KernelVersion, option.Config.ProcFS) if err != nil { return err @@ -420,33 +420,33 @@ func observerLoadInstance(bpfDir string, load *program.Program) error { "kern_version": version, }).Debugf("observerLoadInstance %s %d", load.Name, version) if load.Type == "tracepoint" { - err = loadInstance(bpfDir, load, version, option.Config.Verbosity) + err = loadInstance(bpfDir, load, maps, version, option.Config.Verbosity) if err != nil { l.WithField( "tracepoint", load.Name, ).Info("Failed to load, trying to remove and retrying") load.Unload(true) - err = loadInstance(bpfDir, load, version, option.Config.Verbosity) + err = loadInstance(bpfDir, load, maps, version, option.Config.Verbosity) } if err != nil { return fmt.Errorf("failed prog %s kern_version %d LoadTracingProgram: %w", load.Name, version, err) } } else if load.Type == "raw_tracepoint" || load.Type == "raw_tp" { - err = loadInstance(bpfDir, load, version, option.Config.Verbosity) + err = loadInstance(bpfDir, load, maps, version, option.Config.Verbosity) if err != nil { l.WithField( "raw_tracepoint", load.Name, ).Info("Failed to load, trying to remove and retrying") load.Unload(true) - err = loadInstance(bpfDir, load, version, option.Config.Verbosity) + err = loadInstance(bpfDir, load, maps, version, option.Config.Verbosity) } if err != nil { return fmt.Errorf("failed prog %s kern_version %d LoadRawTracepointProgram: %w", load.Name, version, err) } } else { - err = loadInstance(bpfDir, load, version, option.Config.Verbosity) + err = loadInstance(bpfDir, load, maps, version, option.Config.Verbosity) if err != nil && load.ErrorFatal { return fmt.Errorf("failed prog %s kern_version %d loadInstance: %w", load.Name, version, err) @@ -455,7 +455,7 @@ func observerLoadInstance(bpfDir string, load *program.Program) error { return nil } -func loadInstance(bpfDir string, load *program.Program, version, verbose int) error { +func loadInstance(bpfDir string, load *program.Program, maps []*program.Map, version, verbose int) error { // Check if the load.type is a standard program type. If so, use the standard loader. loadFn, ok := standardTypes[load.Type] if ok { @@ -463,7 +463,7 @@ func loadInstance(bpfDir string, load *program.Program, version, verbose int) er WithField("Type", load.Type). WithField("Attach", load.Attach). Debug("Loading BPF program") - return loadFn(bpfDir, load, verbose) + return loadFn(bpfDir, load, maps, verbose) } // Otherwise, check for a registered probe type. If one exists, use that. probe, ok := registeredProbeLoad[load.Type] @@ -479,6 +479,7 @@ func loadInstance(bpfDir string, load *program.Program, version, verbose int) er Load: load, Version: version, Verbose: verbose, + Maps: maps, }) } diff --git a/pkg/sensors/program/cgroup/cgroup.go b/pkg/sensors/program/cgroup/cgroup.go index a924155b874..2c5e6b81bf8 100644 --- a/pkg/sensors/program/cgroup/cgroup.go +++ b/pkg/sensors/program/cgroup/cgroup.go @@ -20,14 +20,14 @@ var ( func LoadSockOpt( bpfDir string, - load *program.Program, verbose int, + load *program.Program, maps []*program.Map, verbose int, ) error { - return LoadCgroupProgram(bpfDir, load, verbose) + return LoadCgroupProgram(bpfDir, load, maps, verbose) } func LoadCgroupProgram( bpfDir string, - load *program.Program, verbose int) error { + load *program.Program, maps []*program.Map, verbose int) error { if fgsCgroupFD < 0 { fd, err := unix.Open(fgsCgroupPath, unix.O_RDONLY, 0) if err != nil { @@ -35,5 +35,5 @@ func LoadCgroupProgram( } fgsCgroupFD = fd } - return program.LoadProgram(bpfDir, load, program.RawAttach(fgsCgroupFD), verbose) + return program.LoadProgram(bpfDir, load, maps, program.RawAttach(fgsCgroupFD), verbose) } diff --git a/pkg/sensors/program/loader.go b/pkg/sensors/program/loader.go index f396949eca9..9eaf0a644a7 100644 --- a/pkg/sensors/program/loader.go +++ b/pkg/sensors/program/loader.go @@ -532,24 +532,27 @@ func MultiKprobeAttach(load *Program, bpfDir string) AttachFunc { } } -func LoadTracepointProgram(bpfDir string, load *Program, verbose int) error { +func LoadTracepointProgram(bpfDir string, load *Program, maps []*Map, verbose int) error { opts := &LoadOpts{ Attach: TracepointAttach(load, bpfDir), + Maps: maps, } return loadProgram(bpfDir, load, opts, verbose) } -func LoadRawTracepointProgram(bpfDir string, load *Program, verbose int) error { +func LoadRawTracepointProgram(bpfDir string, load *Program, maps []*Map, verbose int) error { opts := &LoadOpts{ Attach: RawTracepointAttach(load), + Maps: maps, } return loadProgram(bpfDir, load, opts, verbose) } -func LoadKprobeProgram(bpfDir string, load *Program, verbose int) error { +func LoadKprobeProgram(bpfDir string, load *Program, maps []*Map, verbose int) error { opts := &LoadOpts{ Attach: KprobeAttach(load, bpfDir), Open: KprobeOpen(load), + Maps: maps, } return loadProgram(bpfDir, load, opts, verbose) } @@ -576,29 +579,32 @@ func KprobeAttachMany(load *Program, syms []string, bpfDir string) AttachFunc { } } -func LoadKprobeProgramAttachMany(bpfDir string, load *Program, syms []string, verbose int) error { +func LoadKprobeProgramAttachMany(bpfDir string, load *Program, syms []string, maps []*Map, verbose int) error { opts := &LoadOpts{ Attach: KprobeAttachMany(load, syms, bpfDir), + Maps: maps, } return loadProgram(bpfDir, load, opts, verbose) } -func LoadUprobeProgram(bpfDir string, load *Program, verbose int) error { +func LoadUprobeProgram(bpfDir string, load *Program, maps []*Map, verbose int) error { opts := &LoadOpts{ Attach: UprobeAttach(load), + Maps: maps, } return loadProgram(bpfDir, load, opts, verbose) } -func LoadMultiKprobeProgram(bpfDir string, load *Program, verbose int) error { +func LoadMultiKprobeProgram(bpfDir string, load *Program, maps []*Map, verbose int) error { opts := &LoadOpts{ Attach: MultiKprobeAttach(load, bpfDir), Open: KprobeOpen(load), + Maps: maps, } return loadProgram(bpfDir, load, opts, verbose) } -func LoadFmodRetProgram(bpfDir string, load *Program, progName string, verbose int) error { +func LoadFmodRetProgram(bpfDir string, load *Program, maps []*Map, progName string, verbose int) error { opts := &LoadOpts{ Attach: func( _ *ebpf.Collection, @@ -630,35 +636,40 @@ func LoadFmodRetProgram(bpfDir string, load *Program, progName string, verbose i progSpec.AttachTo = load.Attach return nil }, + Maps: maps, } return loadProgram(bpfDir, load, opts, verbose) } -func LoadTracingProgram(bpfDir string, load *Program, verbose int) error { +func LoadTracingProgram(bpfDir string, load *Program, maps []*Map, verbose int) error { opts := &LoadOpts{ Attach: TracingAttach(load, bpfDir), + Maps: maps, } return loadProgram(bpfDir, load, opts, verbose) } -func LoadLSMProgram(bpfDir string, load *Program, verbose int) error { +func LoadLSMProgram(bpfDir string, load *Program, maps []*Map, verbose int) error { opts := &LoadOpts{ Attach: LSMAttach(), Open: LSMOpen(load), + Maps: maps, } return loadProgram(bpfDir, load, opts, verbose) } -func LoadLSMProgramSimple(bpfDir string, load *Program, verbose int) error { +func LoadLSMProgramSimple(bpfDir string, load *Program, maps []*Map, verbose int) error { opts := &LoadOpts{ Attach: LSMAttach(), + Maps: maps, } return loadProgram(bpfDir, load, opts, verbose) } -func LoadMultiUprobeProgram(bpfDir string, load *Program, verbose int) error { +func LoadMultiUprobeProgram(bpfDir string, load *Program, maps []*Map, verbose int) error { opts := &LoadOpts{ Attach: MultiUprobeAttach(load), + Maps: maps, } return loadProgram(bpfDir, load, opts, verbose) } @@ -1086,10 +1097,11 @@ func loadProgram( func LoadProgram( bpfDir string, load *Program, + maps []*Map, attach AttachFunc, verbose int, ) error { - return loadProgram(bpfDir, load, &LoadOpts{Attach: attach}, verbose) + return loadProgram(bpfDir, load, &LoadOpts{Attach: attach, Maps: maps}, verbose) } func LoadProgramOpts( diff --git a/pkg/sensors/sensors.go b/pkg/sensors/sensors.go index 8cd741f94ad..e2a9cfa1f2d 100644 --- a/pkg/sensors/sensors.go +++ b/pkg/sensors/sensors.go @@ -223,7 +223,7 @@ var ( registeredPolicyHandlers = map[string]policyHandler{} // list of registers loaders, see registerProbeType() registeredProbeLoad = map[string]probeLoader{} - standardTypes = map[string]func(string, *program.Program, int) error{ + standardTypes = map[string]func(string, *program.Program, []*program.Map, int) error{ "tracepoint": program.LoadTracepointProgram, "raw_tracepoint": program.LoadRawTracepointProgram, "raw_tp": program.LoadRawTracepointProgram, @@ -257,6 +257,7 @@ func RegisterProbeType(probeType string, s probeLoader) { type LoadProbeArgs struct { BPFDir string Load *program.Program + Maps []*program.Map Version, Verbose int } diff --git a/pkg/sensors/tracing/enforcer.go b/pkg/sensors/tracing/enforcer.go index 7e154316622..7355dd14fff 100644 --- a/pkg/sensors/tracing/enforcer.go +++ b/pkg/sensors/tracing/enforcer.go @@ -122,9 +122,9 @@ func (kp *enforcerPolicy) PolicyHandler( func (kp *enforcerPolicy) loadSingleEnforcerSensor( kh *enforcerHandler, - bpfDir string, load *program.Program, verbose int, + bpfDir string, load *program.Program, maps []*program.Map, verbose int, ) error { - if err := program.LoadKprobeProgramAttachMany(bpfDir, load, kh.syscallsSyms, verbose); err == nil { + if err := program.LoadKprobeProgramAttachMany(bpfDir, load, kh.syscallsSyms, maps, verbose); err == nil { logger.GetLogger().Infof("Loaded enforcer sensor: %s", load.Attach) } else { return err @@ -134,7 +134,7 @@ func (kp *enforcerPolicy) loadSingleEnforcerSensor( func (kp *enforcerPolicy) loadMultiEnforcerSensor( kh *enforcerHandler, - bpfDir string, load *program.Program, verbose int, + bpfDir string, load *program.Program, maps []*program.Map, verbose int, ) error { data := &program.MultiKprobeAttachData{} @@ -142,7 +142,7 @@ func (kp *enforcerPolicy) loadMultiEnforcerSensor( load.SetAttachData(data) - if err := program.LoadMultiKprobeProgram(bpfDir, load, verbose); err != nil { + if err := program.LoadMultiKprobeProgram(bpfDir, load, maps, verbose); err != nil { return err } @@ -161,14 +161,14 @@ func (kp *enforcerPolicy) LoadProbe(args sensors.LoadProbeArgs) error { return fmt.Errorf("failed to get enforcer handler for '%s'", name) } if args.Load.Label == "kprobe.multi/enforcer" { - return kp.loadMultiEnforcerSensor(kh, args.BPFDir, args.Load, args.Verbose) + return kp.loadMultiEnforcerSensor(kh, args.BPFDir, args.Load, args.Maps, args.Verbose) } if args.Load.Label == "kprobe/enforcer" { - return kp.loadSingleEnforcerSensor(kh, args.BPFDir, args.Load, args.Verbose) + return kp.loadSingleEnforcerSensor(kh, args.BPFDir, args.Load, args.Maps, args.Verbose) } if strings.HasPrefix(args.Load.Label, "fmod_ret/") { - return program.LoadFmodRetProgram(args.BPFDir, args.Load, "fmodret_enforcer", args.Verbose) + return program.LoadFmodRetProgram(args.BPFDir, args.Load, args.Maps, "fmodret_enforcer", args.Verbose) } return fmt.Errorf("enforcer loader: unknown label: %s", args.Load.Label) diff --git a/pkg/sensors/tracing/generickprobe.go b/pkg/sensors/tracing/generickprobe.go index 0b7a7f97222..40a22551938 100644 --- a/pkg/sensors/tracing/generickprobe.go +++ b/pkg/sensors/tracing/generickprobe.go @@ -1088,7 +1088,7 @@ func getMapLoad(load *program.Program, kprobeEntry *genericKprobe, index uint32) return selectorsMaploads(state, index) } -func loadSingleKprobeSensor(id idtable.EntryID, bpfDir string, load *program.Program, verbose int) error { +func loadSingleKprobeSensor(id idtable.EntryID, bpfDir string, load *program.Program, maps []*program.Map, verbose int) error { gk, err := genericKprobeTableGet(id) if err != nil { return err @@ -1107,7 +1107,7 @@ func loadSingleKprobeSensor(id idtable.EntryID, bpfDir string, load *program.Pro } load.MapLoad = append(load.MapLoad, config) - if err := program.LoadKprobeProgram(bpfDir, load, verbose); err == nil { + if err := program.LoadKprobeProgram(bpfDir, load, maps, verbose); err == nil { logger.GetLogger().Infof("Loaded generic kprobe program: %s -> %s", load.Name, load.Attach) } else { return err @@ -1116,7 +1116,7 @@ func loadSingleKprobeSensor(id idtable.EntryID, bpfDir string, load *program.Pro return err } -func loadMultiKprobeSensor(ids []idtable.EntryID, bpfDir string, load *program.Program, verbose int) error { +func loadMultiKprobeSensor(ids []idtable.EntryID, bpfDir string, load *program.Program, maps []*program.Map, verbose int) error { bin_buf := make([]bytes.Buffer, len(ids)) data := &program.MultiKprobeAttachData{} @@ -1151,7 +1151,7 @@ func loadMultiKprobeSensor(ids []idtable.EntryID, bpfDir string, load *program.P load.OverrideFmodRet = false load.SetAttachData(data) - if err := program.LoadMultiKprobeProgram(bpfDir, load, verbose); err == nil { + if err := program.LoadMultiKprobeProgram(bpfDir, load, maps, verbose); err == nil { logger.GetLogger().Infof("Loaded generic kprobe sensor: %s -> %s", load.Name, load.Attach) } else { return err @@ -1160,12 +1160,12 @@ func loadMultiKprobeSensor(ids []idtable.EntryID, bpfDir string, load *program.P return nil } -func loadGenericKprobeSensor(bpfDir string, load *program.Program, verbose int) error { +func loadGenericKprobeSensor(bpfDir string, load *program.Program, maps []*program.Map, verbose int) error { if id, ok := load.LoaderData.(idtable.EntryID); ok { - return loadSingleKprobeSensor(id, bpfDir, load, verbose) + return loadSingleKprobeSensor(id, bpfDir, load, maps, verbose) } if ids, ok := load.LoaderData.([]idtable.EntryID); ok { - return loadMultiKprobeSensor(ids, bpfDir, load, verbose) + return loadMultiKprobeSensor(ids, bpfDir, load, maps, verbose) } return fmt.Errorf("invalid loadData type: expecting idtable.EntryID/[] and got: %T (%v)", load.LoaderData, load.LoaderData) @@ -1389,7 +1389,7 @@ func retprobeMerge(prev pendingEvent, curr pendingEvent) *tracing.MsgGenericKpro } func (k *observerKprobeSensor) LoadProbe(args sensors.LoadProbeArgs) error { - return loadGenericKprobeSensor(args.BPFDir, args.Load, args.Verbose) + return loadGenericKprobeSensor(args.BPFDir, args.Load, args.Maps, args.Verbose) } func selectorsHaveRateLimit(selectors []v1alpha1.KProbeSelector) bool { diff --git a/pkg/sensors/tracing/genericlsm.go b/pkg/sensors/tracing/genericlsm.go index 699ba08b2ea..1f2a59268fd 100644 --- a/pkg/sensors/tracing/genericlsm.go +++ b/pkg/sensors/tracing/genericlsm.go @@ -99,7 +99,7 @@ func (k *observerLsmSensor) LoadProbe(args sensors.LoadProbeArgs) error { } args.Load.MapLoad = append(args.Load.MapLoad, config) - if err := program.LoadLSMProgram(args.BPFDir, args.Load, args.Verbose); err == nil { + if err := program.LoadLSMProgram(args.BPFDir, args.Load, args.Maps, args.Verbose); err == nil { logger.GetLogger().Infof("Loaded generic LSM program: %s -> %s", args.Load.Name, args.Load.Attach) } else { return err diff --git a/pkg/sensors/tracing/generictracepoint.go b/pkg/sensors/tracing/generictracepoint.go index 2ddab7967ea..0c991a65e5d 100644 --- a/pkg/sensors/tracing/generictracepoint.go +++ b/pkg/sensors/tracing/generictracepoint.go @@ -672,7 +672,7 @@ func (tp *genericTracepoint) EventConfig() (api.EventConfig, error) { return config, nil } -func LoadGenericTracepointSensor(bpfDir string, load *program.Program, verbose int) error { +func LoadGenericTracepointSensor(bpfDir string, load *program.Program, maps []*program.Map, verbose int) error { tracepointLog = logger.GetLogger() @@ -703,7 +703,7 @@ func LoadGenericTracepointSensor(bpfDir string, load *program.Program, verbose i } load.MapLoad = append(load.MapLoad, cfg) - if err := program.LoadTracepointProgram(bpfDir, load, verbose); err == nil { + if err := program.LoadTracepointProgram(bpfDir, load, maps, verbose); err == nil { logger.GetLogger().Infof("Loaded generic tracepoint program: %s -> %s", load.Name, load.Attach) } else { return err @@ -924,5 +924,5 @@ func handleMsgGenericTracepoint( } func (t *observerTracepointSensor) LoadProbe(args sensors.LoadProbeArgs) error { - return LoadGenericTracepointSensor(args.BPFDir, args.Load, args.Verbose) + return LoadGenericTracepointSensor(args.BPFDir, args.Load, args.Maps, args.Verbose) } diff --git a/pkg/sensors/tracing/genericuprobe.go b/pkg/sensors/tracing/genericuprobe.go index 3406ff772e7..b830b6ef644 100644 --- a/pkg/sensors/tracing/genericuprobe.go +++ b/pkg/sensors/tracing/genericuprobe.go @@ -140,7 +140,7 @@ func loadSingleUprobeSensor(uprobeEntry *genericUprobe, args sensors.LoadProbeAr load.MapLoad = append(load.MapLoad, mapLoad...) - if err := program.LoadUprobeProgram(args.BPFDir, args.Load, args.Verbose); err != nil { + if err := program.LoadUprobeProgram(args.BPFDir, args.Load, args.Maps, args.Verbose); err != nil { return err } @@ -198,7 +198,7 @@ func loadMultiUprobeSensor(ids []idtable.EntryID, args sensors.LoadProbeArgs) er load.SetAttachData(data) - if err := program.LoadMultiUprobeProgram(args.BPFDir, args.Load, args.Verbose); err == nil { + if err := program.LoadMultiUprobeProgram(args.BPFDir, args.Load, args.Maps, args.Verbose); err == nil { logger.GetLogger().Infof("Loaded generic uprobe sensor: %s -> %s", load.Name, load.Attach) } else { return err diff --git a/pkg/sensors/tracing/loader.go b/pkg/sensors/tracing/loader.go index 43fe98d0df6..1e1e7b3e8af 100644 --- a/pkg/sensors/tracing/loader.go +++ b/pkg/sensors/tracing/loader.go @@ -180,7 +180,7 @@ func (k *loaderSensor) LoadProbe(args sensors.LoadProbeArgs) error { if err := createLoaderEvents(); err != nil { return err } - return program.LoadKprobeProgram(args.BPFDir, args.Load, args.Verbose) + return program.LoadKprobeProgram(args.BPFDir, args.Load, args.Maps, args.Verbose) } return nil } From 59f4271b88e5d799c4a3c436b94133210959815c Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 22 Jan 2025 22:49:31 +0000 Subject: [PATCH 3/6] tetragon: Factor user maps Now that the loader can access all sensor maps we no longer need to pin user maps to programs. Also for static maps we can add new program.MapUserFrom interface where it's enough just to pass map pointer to create its user map. Signed-off-by: Jiri Olsa --- pkg/sensors/program/map.go | 24 ++++++++++++++++-------- pkg/sensors/test/sensors_test.go | 32 ++++++++++++++++++++++++++++++++ pkg/sensors/tracing/enforcer.go | 16 ++++++++-------- 3 files changed, 56 insertions(+), 16 deletions(-) diff --git a/pkg/sensors/program/map.go b/pkg/sensors/program/map.go index 70278b3006f..d999e9a2680 100644 --- a/pkg/sensors/program/map.go +++ b/pkg/sensors/program/map.go @@ -194,20 +194,28 @@ func MapBuilderOpts(name string, opts MapOpts, lds ...*Program) *Map { return mapBuilder(name, opts.Type, opts.Owner, lds...) } -func MapUser(name string, lds ...*Program) *Map { - return mapBuilder(name, MapTypeGlobal, false, lds...) +func mapUser(name string, ty MapType, prog *Program) *Map { + return &Map{name, "", prog, Idle(), nil, MaxEntries{0, false}, MaxEntries{0, false}, ty, false} } -func MapUserProgram(name string, lds ...*Program) *Map { - return mapBuilder(name, MapTypeProgram, false, lds...) +func MapUser(name string, prog *Program) *Map { + return mapUser(name, MapTypeGlobal, prog) } -func MapUserSensor(name string, lds ...*Program) *Map { - return mapBuilder(name, MapTypeSensor, false, lds...) +func MapUserProgram(name string, prog *Program) *Map { + return mapUser(name, MapTypeProgram, prog) } -func MapUserPolicy(name string, lds ...*Program) *Map { - return mapBuilder(name, MapTypePolicy, false, lds...) +func MapUserSensor(name string, prog *Program) *Map { + return mapUser(name, MapTypeSensor, prog) +} + +func MapUserPolicy(name string, prog *Program) *Map { + return mapUser(name, MapTypePolicy, prog) +} + +func MapUserFrom(m *Map) *Map { + return mapUser(m.Name, m.Type, m.Prog) } func PolicyMapPath(mapDir, policy, name string) string { diff --git a/pkg/sensors/test/sensors_test.go b/pkg/sensors/test/sensors_test.go index 1ddeb01feb9..6050afccac9 100644 --- a/pkg/sensors/test/sensors_test.go +++ b/pkg/sensors/test/sensors_test.go @@ -291,6 +291,38 @@ func TestMapUser(t *testing.T) { assert.NoError(t, err) }) + // Create sensor with user map (via MapUser builder) and make sure + // it's properly loaded + t.Run("ok_from", func(t *testing.T) { + m1 := program.MapBuilder("m1", p1) + m2 := program.MapBuilder("m2", p2) + + s1 := &sensors.Sensor{ + Name: "sensor1", + Progs: []*program.Program{p1}, + Maps: []*program.Map{m1, m2}, + Policy: "policy", + } + + // user map + m1User := program.MapUserFrom(m1) + + s2 := &sensors.Sensor{ + Name: "sensor2", + Progs: []*program.Program{p2}, + Maps: []*program.Map{m1User}, + Policy: "policy", + } + + err = s1.Load(bpf.MapPrefixPath()) + defer s1.Unload(true) + assert.NoError(t, err) + + err = s2.Load(bpf.MapPrefixPath()) + defer s2.Unload(true) + assert.NoError(t, err) + }) + // Create sensor with user map with wrong name (no existing pinned // map file) and make sure the sensor fails to load t.Run("fail_name", func(t *testing.T) { diff --git a/pkg/sensors/tracing/enforcer.go b/pkg/sensors/tracing/enforcer.go index 7355dd14fff..5644f6202c0 100644 --- a/pkg/sensors/tracing/enforcer.go +++ b/pkg/sensors/tracing/enforcer.go @@ -50,21 +50,21 @@ func init() { sensors.RegisterPolicyHandlerAtInit("enforcer", gEnforcerPolicy) } -func enforcerMapsUser(load ...*program.Program) []*program.Map { - edm := program.MapUserPolicy(enforcerDataMapName, load...) +func enforcerMapsUser(load *program.Program) []*program.Map { + edm := program.MapUserPolicy(enforcerDataMapName, load) edm.SetMaxEntries(enforcerMapMaxEntries) return []*program.Map{ edm, - program.MapUserPolicy(enforcermetrics.EnforcerMissedMapName, load...), + program.MapUserPolicy(enforcermetrics.EnforcerMissedMapName, load), } } -func enforcerMaps(load ...*program.Program) []*program.Map { - edm := program.MapBuilderPolicy(enforcerDataMapName, load...) +func enforcerMaps(load *program.Program) []*program.Map { + edm := program.MapBuilderPolicy(enforcerDataMapName, load) edm.SetMaxEntries(enforcerMapMaxEntries) return []*program.Map{ edm, - program.MapBuilderPolicy(enforcermetrics.EnforcerMissedMapName, load...), + program.MapBuilderPolicy(enforcermetrics.EnforcerMissedMapName, load), } } @@ -316,6 +316,7 @@ func (kp *enforcerPolicy) createEnforcerSensor( SetPolicy(policyName) progs = append(progs, load) + maps = append(maps, enforcerMaps(load)...) case OverrideMethodFmodRet: // for fmod_ret, we need one program per syscall logger.GetLogger().Infof("enforcer: using fmod_ret") @@ -329,13 +330,12 @@ func (kp *enforcerPolicy) createEnforcerSensor( SetLoaderData(policyName). SetPolicy(policyName) progs = append(progs, load) + maps = append(maps, enforcerMaps(load)...) } default: return nil, fmt.Errorf("unexpected override method: %d", overrideMethod) } - maps = append(maps, enforcerMaps(progs...)...) - if ok := kp.enforcerAdd(policyName, kh); !ok { return nil, fmt.Errorf("failed to add enforcer: '%s'", policyName) } From c8ba18b797f0a2668b986e03ece4b67ad11e37c0 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 28 Jan 2025 12:08:30 +0000 Subject: [PATCH 4/6] tetragon: Display owner info when printing map object Adding owner info when printing map object, like: Map{Name:m1 PinPath:m1 Owner: false} Signed-off-by: Jiri Olsa --- pkg/sensors/program/map.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/sensors/program/map.go b/pkg/sensors/program/map.go index d999e9a2680..58802b85ad6 100644 --- a/pkg/sensors/program/map.go +++ b/pkg/sensors/program/map.go @@ -105,7 +105,7 @@ type Map struct { } func (m *Map) String() string { - return fmt.Sprintf("Map{Name:%s PinPath:%s}", m.Name, m.PinPath) + return fmt.Sprintf("Map{Name:%s PinPath:%s Owner: %t}", m.Name, m.PinPath, m.IsOwner()) } // globalMaps keeps a record of all global maps to exclude them from per policy From 47031e3ca355137e5ae430be33473872fe695c3c Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 13 Jan 2025 13:58:18 +0000 Subject: [PATCH 5/6] tetragon: Allow to setup execve_map max entries Adding support to allow to setup execve_map max entries, so we can control the size of this map. Signed-off-by: Jiri Olsa --- bpf/lib/process.h | 2 +- pkg/sensors/base/base.go | 12 +++++++++--- pkg/sensors/test/cgroups.go | 2 ++ pkg/sensors/tracing/generickprobe.go | 3 +++ pkg/sensors/tracing/genericlsm.go | 3 +++ pkg/sensors/tracing/generictracepoint.go | 3 +++ pkg/sensors/tracing/genericuprobe.go | 3 +++ pkg/sensors/tracing/loader.go | 6 ++++-- 8 files changed, 28 insertions(+), 6 deletions(-) diff --git a/bpf/lib/process.h b/bpf/lib/process.h index 3ced405f60e..240c8145eb4 100644 --- a/bpf/lib/process.h +++ b/bpf/lib/process.h @@ -366,7 +366,7 @@ struct { struct { __uint(type, BPF_MAP_TYPE_HASH); - __uint(max_entries, 32768); + __uint(max_entries, 1); __type(key, __u32); __type(value, struct execve_map_value); } execve_map SEC(".maps"); diff --git a/pkg/sensors/base/base.go b/pkg/sensors/base/base.go index dc8cf106fbb..f080fde22a5 100644 --- a/pkg/sensors/base/base.go +++ b/pkg/sensors/base/base.go @@ -17,6 +17,10 @@ import ( "github.com/cilium/tetragon/pkg/sensors/program" ) +const ( + execveMapMaxEntries = 32768 +) + var ( basePolicy = "__base__" @@ -55,7 +59,7 @@ var ( /* Event Ring map */ TCPMonMap = program.MapBuilder("tcpmon_map", Execve) /* Networking and Process Monitoring maps */ - ExecveMap = program.MapBuilder("execve_map", Execve) + ExecveMap = program.MapBuilder("execve_map", Execve, Exit, Fork, ExecveBprmCommit) ExecveTailCallsMap = program.MapBuilderProgram("execve_calls", Execve) ExecveJoinMap = program.MapBuilder("tg_execve_joined_info_map", ExecveBprmCommit) @@ -73,7 +77,7 @@ var ( ErrMetricsMap = program.MapBuilder(errmetrics.MapName, Execve) ) -func setupPrograms() { +func setupSensor() { // exit program function ks, err := ksyms.KernelSymbols() if err == nil { @@ -92,6 +96,8 @@ func setupPrograms() { } } logger.GetLogger().Infof("Exit probe on %s", Exit.Attach) + + ExecveMap.SetMaxEntries(execveMapMaxEntries) } func GetExecveMap() *program.Map { @@ -137,7 +143,7 @@ func initBaseSensor() *sensors.Sensor { sensor := sensors.Sensor{ Name: basePolicy, } - setupPrograms() + setupSensor() sensor.Progs = GetDefaultPrograms() sensor.Maps = GetDefaultMaps() return ApplyExtensions(&sensor) diff --git a/pkg/sensors/test/cgroups.go b/pkg/sensors/test/cgroups.go index 7c98bb2a40e..4eded504093 100644 --- a/pkg/sensors/test/cgroups.go +++ b/pkg/sensors/test/cgroups.go @@ -5,6 +5,7 @@ package test import ( "github.com/cilium/tetragon/pkg/sensors" + "github.com/cilium/tetragon/pkg/sensors/base" "github.com/cilium/tetragon/pkg/sensors/program" ) @@ -53,6 +54,7 @@ func getCgroupPrograms() []*program.Program { func getCgroupMaps() []*program.Map { maps := []*program.Map{ GetCgroupsTrackingMap(), + program.MapUserFrom(base.ExecveMap), } return maps } diff --git a/pkg/sensors/tracing/generickprobe.go b/pkg/sensors/tracing/generickprobe.go index 40a22551938..1465608565c 100644 --- a/pkg/sensors/tracing/generickprobe.go +++ b/pkg/sensors/tracing/generickprobe.go @@ -35,6 +35,7 @@ import ( "github.com/cilium/tetragon/pkg/policyfilter" "github.com/cilium/tetragon/pkg/selectors" "github.com/cilium/tetragon/pkg/sensors" + "github.com/cilium/tetragon/pkg/sensors/base" "github.com/cilium/tetragon/pkg/sensors/program" lru "github.com/hashicorp/golang-lru/v2" "github.com/sirupsen/logrus" @@ -665,6 +666,8 @@ func createGenericKprobeSensor( return nil, err } + maps = append(maps, program.MapUserFrom(base.ExecveMap)) + return &sensors.Sensor{ Name: name, Progs: progs, diff --git a/pkg/sensors/tracing/genericlsm.go b/pkg/sensors/tracing/genericlsm.go index 1f2a59268fd..a00da783f31 100644 --- a/pkg/sensors/tracing/genericlsm.go +++ b/pkg/sensors/tracing/genericlsm.go @@ -27,6 +27,7 @@ import ( "github.com/cilium/tetragon/pkg/policyfilter" "github.com/cilium/tetragon/pkg/selectors" "github.com/cilium/tetragon/pkg/sensors" + "github.com/cilium/tetragon/pkg/sensors/base" "github.com/cilium/tetragon/pkg/sensors/program" ) @@ -364,6 +365,8 @@ func createGenericLsmSensor( return nil, err } + maps = append(maps, program.MapUserFrom(base.ExecveMap)) + return &sensors.Sensor{ Name: name, Progs: progs, diff --git a/pkg/sensors/tracing/generictracepoint.go b/pkg/sensors/tracing/generictracepoint.go index 0c991a65e5d..a2ec9e431db 100644 --- a/pkg/sensors/tracing/generictracepoint.go +++ b/pkg/sensors/tracing/generictracepoint.go @@ -29,6 +29,7 @@ import ( "github.com/cilium/tetragon/pkg/reader/network" "github.com/cilium/tetragon/pkg/selectors" "github.com/cilium/tetragon/pkg/sensors" + "github.com/cilium/tetragon/pkg/sensors/base" "github.com/cilium/tetragon/pkg/sensors/program" "github.com/cilium/tetragon/pkg/syscallinfo" "github.com/cilium/tetragon/pkg/tracepoint" @@ -583,6 +584,8 @@ func createGenericTracepointSensor( maps = append(maps, selMatchBinariesMap) } + maps = append(maps, program.MapUserFrom(base.ExecveMap)) + ret.Progs = progs ret.Maps = maps return ret, nil diff --git a/pkg/sensors/tracing/genericuprobe.go b/pkg/sensors/tracing/genericuprobe.go index b830b6ef644..d924769ca65 100644 --- a/pkg/sensors/tracing/genericuprobe.go +++ b/pkg/sensors/tracing/genericuprobe.go @@ -24,6 +24,7 @@ import ( "github.com/cilium/tetragon/pkg/option" "github.com/cilium/tetragon/pkg/selectors" "github.com/cilium/tetragon/pkg/sensors" + "github.com/cilium/tetragon/pkg/sensors/base" "github.com/cilium/tetragon/pkg/sensors/program" ) @@ -284,6 +285,8 @@ func createGenericUprobeSensor( return nil, err } + maps = append(maps, program.MapUserFrom(base.ExecveMap)) + return &sensors.Sensor{ Name: name, Progs: progs, diff --git a/pkg/sensors/tracing/loader.go b/pkg/sensors/tracing/loader.go index 1e1e7b3e8af..5b39128be15 100644 --- a/pkg/sensors/tracing/loader.go +++ b/pkg/sensors/tracing/loader.go @@ -42,6 +42,7 @@ import ( "github.com/cilium/tetragon/pkg/observer" "github.com/cilium/tetragon/pkg/policyfilter" "github.com/cilium/tetragon/pkg/sensors" + "github.com/cilium/tetragon/pkg/sensors/base" "github.com/cilium/tetragon/pkg/sensors/program" "github.com/cilium/tetragon/pkg/strutils" "github.com/cilium/tetragon/pkg/tracingpolicy" @@ -67,7 +68,8 @@ var ( "loader", ) - idsMap = program.MapBuilder("ids_map", loader) + idsMap = program.MapBuilder("ids_map", loader) + execveMap = program.MapUserFrom(base.ExecveMap) loaderEnabled bool @@ -104,7 +106,7 @@ func GetLoaderSensor() *sensors.Sensor { return &sensors.Sensor{ Name: "__loader__", Progs: []*program.Program{loader}, - Maps: []*program.Map{idsMap}, + Maps: []*program.Map{idsMap, execveMap}, } } From da0b16e840d753493f2403e0ef77a447f571cfbb Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 6 Jan 2025 22:59:19 +0000 Subject: [PATCH 6/6] tetragon: Add execve-map-entries option Adding execve-map-entries option to setup entries of execve_map map. Signed-off-by: Jiri Olsa --- docs/data/tetragon_flags.yaml | 3 ++ pkg/option/config.go | 2 + pkg/option/flags.go | 5 ++ pkg/sensors/base/base.go | 54 +++++++++++++++++++++- pkg/sensors/exec/procevents/proc_reader.go | 16 ++++++- 5 files changed, 77 insertions(+), 3 deletions(-) diff --git a/docs/data/tetragon_flags.yaml b/docs/data/tetragon_flags.yaml index 7a27fa4c60d..88af3e2d93a 100644 --- a/docs/data/tetragon_flags.yaml +++ b/docs/data/tetragon_flags.yaml @@ -95,6 +95,9 @@ options: - name: event-queue-size default_value: "10000" usage: Set the size of the internal event queue. + - name: execve-map-entries + default_value: "32768" + usage: Set entries for execve_map table (entries/size/max) - name: export-aggregation-buffer-size default_value: "10000" usage: Aggregator channel buffer size diff --git a/pkg/option/config.go b/pkg/option/config.go index 30871885afc..560692461c4 100644 --- a/pkg/option/config.go +++ b/pkg/option/config.go @@ -110,6 +110,8 @@ type config struct { EventCacheRetryDelay int CompatibilitySyscall64SizeType bool + + ExecveMapEntries string } var ( diff --git a/pkg/option/flags.go b/pkg/option/flags.go index 05a72d0e2a4..4ae0e040fc5 100644 --- a/pkg/option/flags.go +++ b/pkg/option/flags.go @@ -118,6 +118,8 @@ const ( KeyEventCacheRetryDelay = "event-cache-retry-delay" KeyCompatibilitySyscall64SizeType = "enable-compatibility-syscall64-size-type" + + KeyExecveMapEntries = "execve-map-entries" ) type UsernameMetadaCode int @@ -252,6 +254,7 @@ func ReadAndSetFlags() error { Config.CompatibilitySyscall64SizeType = viper.GetBool(KeyCompatibilitySyscall64SizeType) + Config.ExecveMapEntries = viper.GetString(KeyExecveMapEntries) return nil } @@ -419,4 +422,6 @@ func AddFlags(flags *pflag.FlagSet) { flags.Int(KeyEventCacheRetryDelay, defaults.DefaultEventCacheRetryDelay, "Delay in seconds between event cache retries") flags.Bool(KeyCompatibilitySyscall64SizeType, false, "syscall64 type will produce output of type size (compatibility flag, will be removed in v1.4)") + + flags.String(KeyExecveMapEntries, "32768", "Set entries for execve_map table (entries/size/max)") } diff --git a/pkg/sensors/base/base.go b/pkg/sensors/base/base.go index f080fde22a5..158a4fe5dfc 100644 --- a/pkg/sensors/base/base.go +++ b/pkg/sensors/base/base.go @@ -5,20 +5,27 @@ package base import ( "log" + "os" + "strconv" + "strings" "sync" "testing" + "unsafe" "github.com/cilium/tetragon/pkg/errmetrics" "github.com/cilium/tetragon/pkg/ksyms" "github.com/cilium/tetragon/pkg/logger" "github.com/cilium/tetragon/pkg/mbset" + "github.com/cilium/tetragon/pkg/option" "github.com/cilium/tetragon/pkg/sensors" "github.com/cilium/tetragon/pkg/sensors/exec/config" + "github.com/cilium/tetragon/pkg/sensors/exec/execvemap" "github.com/cilium/tetragon/pkg/sensors/program" + "github.com/cilium/tetragon/pkg/strutils" ) const ( - execveMapMaxEntries = 32768 + ExecveMapMaxEntries = 32768 ) var ( @@ -77,6 +84,43 @@ var ( ErrMetricsMap = program.MapBuilder(errmetrics.MapName, Execve) ) +func readThreadsMax(path string) (int64, error) { + data, err := os.ReadFile(path) + if err != nil { + return 0, err + } + str := strings.TrimRight(string(data), "\n") + return strconv.ParseInt(str, 10, 32) +} + +func GetExecveMapEntries(str string) int { + entry := int(unsafe.Sizeof(execvemap.ExecveValue{})) + + if len(str) == 0 { + return ExecveMapMaxEntries + } + // pure number of entries + if val, err := strconv.ParseUint(str, 10, 32); err == nil { + return int(val) + } + // follow threads-max entries + if str == "max" { + if val, err := readThreadsMax("/proc/sys/kernel/threads-max"); err == nil { + return int(val) + } + logger.GetLogger().Warn("Failed to read /proc/sys/kernel/threads-max file, falling back to default") + return ExecveMapMaxEntries + } + // set entries based on size + size, err := strutils.ParseSize(str) + if err != nil { + logger.GetLogger().Warn("Failed to parse --execve-map-max value, falling back to default") + return ExecveMapMaxEntries + } + val := size / entry + return val +} + func setupSensor() { // exit program function ks, err := ksyms.KernelSymbols() @@ -97,7 +141,13 @@ func setupSensor() { } logger.GetLogger().Infof("Exit probe on %s", Exit.Attach) - ExecveMap.SetMaxEntries(execveMapMaxEntries) + entries := GetExecveMapEntries(option.Config.ExecveMapEntries) + ExecveMap.SetMaxEntries(entries) + + logger.GetLogger(). + WithField("size", strutils.SizeWithSuffix(entries*int(unsafe.Sizeof(execvemap.ExecveValue{})))). + WithField("config", option.Config.ExecveMapEntries). + Infof("Set execve_map entries %d", entries) } func GetExecveMap() *program.Map { diff --git a/pkg/sensors/exec/procevents/proc_reader.go b/pkg/sensors/exec/procevents/proc_reader.go index 7917338cc84..7faa02c0ec2 100644 --- a/pkg/sensors/exec/procevents/proc_reader.go +++ b/pkg/sensors/exec/procevents/proc_reader.go @@ -370,6 +370,15 @@ func writeExecveMap(procs []procs) { panic(err) } } + + entries, ok := base.ExecveMap.GetMaxEntries() + if !ok { + logger.GetLogger().Warnf("Failed to get number of execve_map entries, using default.") + entries = base.ExecveMapMaxEntries + } + logger.GetLogger().Infof("Maximum execve_map entries %d, need to add %d.", entries, len(procs)) + i := uint32(0) + inInitTree := make(map[uint32]struct{}) for _, p := range procs { k, v := procToKeyValue(p, inInitTree) @@ -377,6 +386,11 @@ func writeExecveMap(procs []procs) { if err != nil { logger.GetLogger().WithField("value", v).WithError(err).Warn("failed to put value in execve_map") } + + i++ + if i == entries { + break + } } // In order for kprobe events from kernel ctx to not abort we need the // execve lookup to map to a valid entry. So to simplify the kernel side @@ -393,7 +407,7 @@ func writeExecveMap(procs []procs) { }) m.Close() - updateExecveMapStats(int64(len(procs))) + updateExecveMapStats(int64(entries)) } func pushEvents(ps []procs) {