From ea3998ee6f7f91c3ee5b44d80638e683ef47678f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Geyslan=20Greg=C3=B3rio?= Date: Mon, 15 Apr 2024 14:25:59 -0300 Subject: [PATCH 1/7] chore: remove dead/duplicate code --- pkg/cmd/cobra/cobra.go | 5 ----- pkg/ebpf/tracee.go | 9 --------- 2 files changed, 14 deletions(-) diff --git a/pkg/cmd/cobra/cobra.go b/pkg/cmd/cobra/cobra.go index 90f3d259e2b0..e963718035c3 100644 --- a/pkg/cmd/cobra/cobra.go +++ b/pkg/cmd/cobra/cobra.go @@ -247,11 +247,6 @@ func GetTraceeRunner(c *cobra.Command, version string) (cmd.Runner, error) { } cfg.Output = output.TraceeConfig - if err != nil { - return runner, err - } - cfg.Output = output.TraceeConfig - // Create printer p, err := printer.NewBroadcast(output.PrinterConfigs, cmd.GetContainerMode(cfg)) diff --git a/pkg/ebpf/tracee.go b/pkg/ebpf/tracee.go index 8356d711eb59..e6100bce582f 100644 --- a/pkg/ebpf/tracee.go +++ b/pkg/ebpf/tracee.go @@ -779,15 +779,6 @@ func (t *Tracee) initDerivationTable() error { return nil } -// RegisterEventDerivation registers an event derivation handler for tracee to use in the event pipeline -func (t *Tracee) RegisterEventDerivation(deriveFrom events.ID, deriveTo events.ID, deriveCondition func() bool, deriveLogic derive.DeriveFunction) error { - if t.eventDerivations == nil { - return errfmt.Errorf("tracee not initialized yet") - } - - return t.eventDerivations.Register(deriveFrom, deriveTo, deriveCondition, deriveLogic) -} - // options config should match defined values in ebpf code const ( optExecEnv uint32 = 1 << iota From e8f4545e8830d8a105eda22517f54caef9d628b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Geyslan=20Greg=C3=B3rio?= Date: Thu, 11 Apr 2024 15:00:09 -0300 Subject: [PATCH 2/7] chore(policy): remove useless code The values returned by the removed methods are only used for computation, so it is unnecessary to expose them. --- pkg/policy/ebpf.go | 8 ++++---- pkg/policy/policies.go | 16 ---------------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/pkg/policy/ebpf.go b/pkg/policy/ebpf.go index 3985fdafad32..25651046dcd6 100644 --- a/pkg/policy/ebpf.go +++ b/pkg/policy/ebpf.go @@ -917,10 +917,10 @@ func (ps *Policies) computePoliciesConfig() *PoliciesConfig { cfg.EnabledScopes |= 1 << offset } - cfg.UidMax = ps.UIDFilterMax() - cfg.UidMin = ps.UIDFilterMin() - cfg.PidMax = ps.PIDFilterMax() - cfg.PidMin = ps.PIDFilterMin() + cfg.UidMax = ps.uidFilterMax + cfg.UidMin = ps.uidFilterMin + cfg.PidMax = ps.pidFilterMax + cfg.PidMin = ps.pidFilterMin return cfg } diff --git a/pkg/policy/policies.go b/pkg/policy/policies.go index 8b9dd261e624..286e9775ce27 100644 --- a/pkg/policy/policies.go +++ b/pkg/policy/policies.go @@ -79,22 +79,6 @@ func (ps *Policies) Count() int { return ps.count() } -func (ps *Policies) UIDFilterMin() uint64 { - return atomic.LoadUint64(&ps.uidFilterMin) -} - -func (ps *Policies) UIDFilterMax() uint64 { - return atomic.LoadUint64(&ps.uidFilterMax) -} - -func (ps *Policies) PIDFilterMin() uint64 { - return atomic.LoadUint64(&ps.pidFilterMin) -} - -func (ps *Policies) PIDFilterMax() uint64 { - return atomic.LoadUint64(&ps.pidFilterMax) -} - func (ps *Policies) SetVersion(version uint16) { atomic.StoreUint32(&ps.version, uint32(version)) } From 78305a90b08b6babb26b19e01fffc2478a9d14b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Geyslan=20Greg=C3=B3rio?= Date: Thu, 11 Apr 2024 15:04:11 -0300 Subject: [PATCH 3/7] chore(policy): remove SetVersion() The field can be set directly, so the method is not needed. --- pkg/policy/policies.go | 8 ++------ pkg/policy/snapshots.go | 2 +- pkg/policy/snapshots_test.go | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/pkg/policy/policies.go b/pkg/policy/policies.go index 286e9775ce27..4d265dc183c4 100644 --- a/pkg/policy/policies.go +++ b/pkg/policy/policies.go @@ -24,7 +24,7 @@ var AlwaysSubmit = events.EventState{ type Policies struct { rwmu sync.RWMutex - version uint32 // updated on snapshot store + version uint16 // updated on snapshot store bpfInnerMaps map[string]*bpf.BPFMapLow // BPF inner maps policiesArray [MaxPolicies]*Policy // underlying policies array for fast access of empty slots policiesMapByID map[int]*Policy // all policies map by ID @@ -79,12 +79,8 @@ func (ps *Policies) Count() int { return ps.count() } -func (ps *Policies) SetVersion(version uint16) { - atomic.StoreUint32(&ps.version, uint32(version)) -} - func (ps *Policies) Version() uint16 { - return uint16(atomic.LoadUint32(&ps.version)) + return ps.version } // ContainerFilterEnabled returns a bitmap of policies that have at least diff --git a/pkg/policy/snapshots.go b/pkg/policy/snapshots.go index f8408cf3fea4..2d2ab4b17125 100644 --- a/pkg/policy/snapshots.go +++ b/pkg/policy/snapshots.go @@ -78,7 +78,7 @@ func (s *snapshots) Store(ps *Policies) { s.lastVersion++ } - ps.SetVersion(s.lastVersion) + ps.version = s.lastVersion // set new version in Policies snap := &snapshot{ time: time.Now(), diff --git a/pkg/policy/snapshots_test.go b/pkg/policy/snapshots_test.go index 6e32789f2d9e..40b3e66b27e9 100644 --- a/pkg/policy/snapshots_test.go +++ b/pkg/policy/snapshots_test.go @@ -96,7 +96,7 @@ func TestCircularBufferOverwrite(t *testing.T) { // store one more snapshot to overwrite the first snapshot in the buffer psOverwrite := &Policies{} Snapshots().Store(psOverwrite) - assert.Equal(t, uint32(maxSnapshots+1), psOverwrite.version) + assert.Equal(t, uint16(maxSnapshots+1), psOverwrite.version) // check if the oldest snapshot (version 1) has been overwritten _, err = Snapshots().Get(1) From 3faa9b88c1d0f4b87bd6d94ac3535068d35e5dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Geyslan=20Greg=C3=B3rio?= Date: Thu, 11 Apr 2024 14:46:25 -0300 Subject: [PATCH 4/7] chore(policy): rename consts and add PolicyNone --- pkg/cmd/flags/policy.go | 4 ++-- pkg/ebpf/policy_manager_test.go | 16 ++++++++-------- pkg/ebpf/tracee.go | 2 +- pkg/policy/errors.go | 4 ++-- pkg/policy/policies.go | 15 ++++++++------- pkg/policy/snapshots.go | 2 +- 6 files changed, 22 insertions(+), 21 deletions(-) diff --git a/pkg/cmd/flags/policy.go b/pkg/cmd/flags/policy.go index 45269e4243bb..7e8a77bd9438 100644 --- a/pkg/cmd/flags/policy.go +++ b/pkg/cmd/flags/policy.go @@ -21,8 +21,8 @@ func PrepareFilterMapsFromPolicies(policies []k8s.PolicyInterface) (PolicyScopeM return nil, nil, errfmt.Errorf("no policies provided") } - if len(policies) > policy.MaxPolicies { - return nil, nil, errfmt.Errorf("too many policies provided, there is a limit of %d policies", policy.MaxPolicies) + if len(policies) > policy.PolicyMax { + return nil, nil, errfmt.Errorf("too many policies provided, there is a limit of %d policies", policy.PolicyMax) } policyNames := make(map[string]bool) diff --git a/pkg/ebpf/policy_manager_test.go b/pkg/ebpf/policy_manager_test.go index c40267e4132e..a1f8fc130415 100644 --- a/pkg/ebpf/policy_manager_test.go +++ b/pkg/ebpf/policy_manager_test.go @@ -83,7 +83,7 @@ func TestPolicyManagerEnableAndDisableRuleConcurrent(t *testing.T) { wg.Add(1) go func() { - for i := 0; i < policy.MaxPolicies; i++ { + for i := 0; i < policy.PolicyMax; i++ { for _, e := range eventsToEnable { policyManager.EnableRule(i, e) } @@ -93,7 +93,7 @@ func TestPolicyManagerEnableAndDisableRuleConcurrent(t *testing.T) { wg.Add(1) go func() { - for i := 0; i < policy.MaxPolicies; i++ { + for i := 0; i < policy.PolicyMax; i++ { for _, e := range eventsToDisable { policyManager.DisableRule(i, e) } @@ -103,12 +103,12 @@ func TestPolicyManagerEnableAndDisableRuleConcurrent(t *testing.T) { wg.Wait() - for i := 0; i < policy.MaxPolicies; i++ { + for i := 0; i < policy.PolicyMax; i++ { for _, e := range eventsToEnable { - assert.True(t, policyManager.IsRuleEnabled(policy.AllPoliciesOn, e)) + assert.True(t, policyManager.IsRuleEnabled(policy.PolicyAll, e)) } for _, e := range eventsToDisable { - assert.False(t, policyManager.IsRuleEnabled(policy.AllPoliciesOn, e)) + assert.False(t, policyManager.IsRuleEnabled(policy.PolicyAll, e)) } } } @@ -182,7 +182,7 @@ func TestPolicyManagerEnableAndDisableEventConcurrent(t *testing.T) { wg.Add(1) go func() { - for i := 0; i < policy.MaxPolicies; i++ { + for i := 0; i < policy.PolicyMax; i++ { for _, e := range eventsToEnable { policyManager.EnableEvent(e) } @@ -192,7 +192,7 @@ func TestPolicyManagerEnableAndDisableEventConcurrent(t *testing.T) { wg.Add(1) go func() { - for i := 0; i < policy.MaxPolicies; i++ { + for i := 0; i < policy.PolicyMax; i++ { for _, e := range eventsToDisable { policyManager.DisableEvent(e) } @@ -202,7 +202,7 @@ func TestPolicyManagerEnableAndDisableEventConcurrent(t *testing.T) { wg.Wait() - for i := 0; i < policy.MaxPolicies; i++ { + for i := 0; i < policy.PolicyMax; i++ { for _, e := range eventsToEnable { assert.True(t, policyManager.IsEventEnabled(e)) } diff --git a/pkg/ebpf/tracee.go b/pkg/ebpf/tracee.go index e6100bce582f..fab3bfc56d80 100644 --- a/pkg/ebpf/tracee.go +++ b/pkg/ebpf/tracee.go @@ -1706,7 +1706,7 @@ func (t *Tracee) triggerMemDumpCall(address uint64, length uint64, eventHandle u // SubscribeAll returns a stream subscribed to all policies func (t *Tracee) SubscribeAll() *streams.Stream { - return t.subscribe(policy.AllPoliciesOn) + return t.subscribe(policy.PolicyAll) } // Subscribe returns a stream subscribed to selected policies diff --git a/pkg/policy/errors.go b/pkg/policy/errors.go index ac78729770a0..220516800490 100644 --- a/pkg/policy/errors.go +++ b/pkg/policy/errors.go @@ -9,11 +9,11 @@ func PolicyNilError() error { } func PoliciesMaxExceededError() error { - return fmt.Errorf("policies maximum exceeded [%d]", MaxPolicies) + return fmt.Errorf("policies maximum exceeded [%d]", PolicyMax) } func PoliciesOutOfRangeError(idx int) error { - return fmt.Errorf("policies index [%d] out-of-range [0-%d]", idx, MaxPolicies-1) + return fmt.Errorf("policies index [%d] out-of-range [0-%d]", idx, PolicyMax-1) } func PolicyAlreadyExistsError(name string, idx int) error { diff --git a/pkg/policy/policies.go b/pkg/policy/policies.go index 4d265dc183c4..14930c143fcc 100644 --- a/pkg/policy/policies.go +++ b/pkg/policy/policies.go @@ -13,12 +13,13 @@ import ( ) const ( - MaxPolicies int = 64 - AllPoliciesOn = ^uint64(0) + PolicyMax = int(64) + PolicyAll = ^uint64(0) + PolicyNone = uint64(0) ) var AlwaysSubmit = events.EventState{ - Submit: AllPoliciesOn, + Submit: PolicyAll, } type Policies struct { @@ -26,7 +27,7 @@ type Policies struct { version uint16 // updated on snapshot store bpfInnerMaps map[string]*bpf.BPFMapLow // BPF inner maps - policiesArray [MaxPolicies]*Policy // underlying policies array for fast access of empty slots + policiesArray [PolicyMax]*Policy // underlying policies array for fast access of empty slots policiesMapByID map[int]*Policy // all policies map by ID policiesMapByName map[string]*Policy // all policies map by name policiesList []*Policy // all policies list @@ -49,7 +50,7 @@ func NewPolicies() *Policies { rwmu: sync.RWMutex{}, version: 0, bpfInnerMaps: map[string]*bpf.BPFMapLow{}, - policiesArray: [MaxPolicies]*Policy{}, + policiesArray: [PolicyMax]*Policy{}, policiesMapByID: map[int]*Policy{}, policiesMapByName: map[string]*Policy{}, policiesList: []*Policy{}, @@ -149,7 +150,7 @@ func (ps *Policies) Add(p *Policy) error { if p == nil { return PolicyNilError() } - if ps.count() == MaxPolicies { + if ps.count() == PolicyMax { return PoliciesMaxExceededError() } if existing, ok := ps.policiesMapByName[p.Name]; ok { @@ -401,5 +402,5 @@ func (ps *Policies) calculateGlobalMinMax() { } func isIDInRange(id int) bool { - return id >= 0 && id < MaxPolicies + return id >= 0 && id < PolicyMax } diff --git a/pkg/policy/snapshots.go b/pkg/policy/snapshots.go index 2d2ab4b17125..e2c0dea5ad6f 100644 --- a/pkg/policy/snapshots.go +++ b/pkg/policy/snapshots.go @@ -9,7 +9,7 @@ import ( ) const ( - maxSnapshots = MaxPolicies + maxSnapshots = PolicyMax ) // snapshot is a snapshot of the Policies at a given version. From 1d17a50651c31d56ef8cfb48d397fd77d8cf00c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Geyslan=20Greg=C3=B3rio?= Date: Thu, 11 Apr 2024 14:32:39 -0300 Subject: [PATCH 5/7] chore(policy): align policy and polices API Both policy and policies now have the same ContainerFilterEnabled() method returning a boolean value. The respective bitmap now is accessed via Policies WithContainerFilterEnabled(). --- pkg/ebpf/events_pipeline.go | 2 +- pkg/policy/policies.go | 12 ++++++++---- pkg/policy/policy.go | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pkg/ebpf/events_pipeline.go b/pkg/ebpf/events_pipeline.go index 8a075b7c5b0e..b593aca870e2 100644 --- a/pkg/ebpf/events_pipeline.go +++ b/pkg/ebpf/events_pipeline.go @@ -466,7 +466,7 @@ func (t *Tracee) processEvents(ctx context.Context, in <-chan *trace.Event) ( } // Get a bitmap with all policies containing container filters - policiesWithContainerFilter := policies.ContainerFilterEnabled() + policiesWithContainerFilter := policies.WithContainerFilterEnabled() // Filter out events that don't have a container ID from all the policies that // have container filters. This will guarantee that any of those policies diff --git a/pkg/policy/policies.go b/pkg/policy/policies.go index 14930c143fcc..fb40cb783191 100644 --- a/pkg/policy/policies.go +++ b/pkg/policy/policies.go @@ -84,10 +84,14 @@ func (ps *Policies) Version() uint16 { return ps.version } -// ContainerFilterEnabled returns a bitmap of policies that have at least -// one container filter type enabled. -func (ps *Policies) ContainerFilterEnabled() uint64 { - return atomic.LoadUint64(&ps.containerFiltersEnabled) +// WithContainerFilterEnabled returns a bitmap of policies that have at least one container filter type enabled. +func (ps *Policies) WithContainerFilterEnabled() uint64 { + return ps.containerFiltersEnabled +} + +// ContainerFilterEnabled returns true if at least one policy has a container filter type enabled. +func (ps *Policies) ContainerFilterEnabled() bool { + return ps.WithContainerFilterEnabled() > 0 } // FilterableInUserland returns a bitmap of policies that must be filtered in userland diff --git a/pkg/policy/policy.go b/pkg/policy/policy.go index 3de3bda43e89..3e21bf8880a0 100644 --- a/pkg/policy/policy.go +++ b/pkg/policy/policy.go @@ -57,7 +57,7 @@ func NewPolicy() *Policy { } } -// ContainerFilterEnabled returns true when the policy has at least one container filter type enabled +// ContainerFilterEnabled returns true if the policy has at least one container filter type enabled. func (p *Policy) ContainerFilterEnabled() bool { return (p.ContFilter.Enabled() && p.ContFilter.Value()) || (p.NewContFilter.Enabled() && p.NewContFilter.Value()) || From 13977144ba25fff53c770e8d6c97f1f99035b903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Geyslan=20Greg=C3=B3rio?= Date: Mon, 15 Apr 2024 16:05:18 -0300 Subject: [PATCH 6/7] chore(cmd): reuse already computed policies value GetContainerMode() can make use of the already computed policies information (container filters) via ContainerFilterEnabled(). --- pkg/cmd/cobra/cobra.go | 5 ++++- pkg/cmd/tracee.go | 24 +++++++++--------------- pkg/cmd/urfave/urfave.go | 5 ++++- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/pkg/cmd/cobra/cobra.go b/pkg/cmd/cobra/cobra.go index e963718035c3..f7cd22139d66 100644 --- a/pkg/cmd/cobra/cobra.go +++ b/pkg/cmd/cobra/cobra.go @@ -249,7 +249,10 @@ func GetTraceeRunner(c *cobra.Command, version string) (cmd.Runner, error) { // Create printer - p, err := printer.NewBroadcast(output.PrinterConfigs, cmd.GetContainerMode(cfg)) + p, err := printer.NewBroadcast( + output.PrinterConfigs, + cmd.GetContainerMode(policies.ContainerFilterEnabled(), cfg.NoContainersEnrich), + ) if err != nil { return runner, err } diff --git a/pkg/cmd/tracee.go b/pkg/cmd/tracee.go index 6818882a5682..6291b65f3435 100644 --- a/pkg/cmd/tracee.go +++ b/pkg/cmd/tracee.go @@ -120,24 +120,18 @@ func (r Runner) Run(ctx context.Context) error { return err } -func GetContainerMode(cfg config.Config) config.ContainerMode { - containerMode := config.ContainerModeDisabled - - for it := cfg.Policies.CreateAllIterator(); it.HasNext(); { - p := it.Next() - if p.ContainerFilterEnabled() { - // Container Enrichment is enabled by default ... - containerMode = config.ContainerModeEnriched - if cfg.NoContainersEnrich { - // ... but might be disabled as a safeguard measure. - containerMode = config.ContainerModeEnabled - } +func GetContainerMode(containerFilterEnabled, noContainersEnrich bool) config.ContainerMode { + if !containerFilterEnabled { + return config.ContainerModeDisabled + } - break - } + // If "no-containers" enrichment is set, return just enabled mode ... + if noContainersEnrich { + return config.ContainerModeEnabled } - return containerMode + // ... otherwise return enriched mode as default. + return config.ContainerModeEnriched } const pidFileName = "tracee.pid" diff --git a/pkg/cmd/urfave/urfave.go b/pkg/cmd/urfave/urfave.go index a8d37476e7e9..9c82380218c2 100644 --- a/pkg/cmd/urfave/urfave.go +++ b/pkg/cmd/urfave/urfave.go @@ -129,7 +129,10 @@ func GetTraceeRunner(c *cli.Context, version string) (cmd.Runner, error) { cfg.Policies = policies policy.Snapshots().Store(cfg.Policies) - broadcast, err := printer.NewBroadcast(output.PrinterConfigs, cmd.GetContainerMode(cfg)) + broadcast, err := printer.NewBroadcast( + output.PrinterConfigs, + cmd.GetContainerMode(policies.ContainerFilterEnabled(), cfg.NoContainersEnrich), + ) if err != nil { return runner, err } From c5f3f8d5a77beb3870b383be109cb063567ae241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Geyslan=20Greg=C3=B3rio?= Date: Mon, 15 Apr 2024 16:34:17 -0300 Subject: [PATCH 7/7] chore(policy): move logic into policies_compute.go This new file contains the logic for policies computation. --- pkg/policy/policies.go | 156 ++------------------------------- pkg/policy/policies_compute.go | 141 +++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 148 deletions(-) create mode 100644 pkg/policy/policies_compute.go diff --git a/pkg/policy/policies.go b/pkg/policy/policies.go index fb40cb783191..3cd0744b1b9f 100644 --- a/pkg/policy/policies.go +++ b/pkg/policy/policies.go @@ -100,38 +100,6 @@ func (ps *Policies) FilterableInUserland() uint64 { return atomic.LoadUint64(&ps.filterableInUserland) } -// compute recalculates values, updates flags, fills the reduced userland map, -// and sets the related bitmap that is used to prevent the iteration of the entire map. -// -// It must be called at initialization and at every runtime policies changes. -func (ps *Policies) compute() { - // update global min and max - ps.calculateGlobalMinMax() - - // update enabled container filter flag - ps.updateContainerFilterEnabled() - - userlandList := []*Policy{} - ps.filterableInUserland = 0 - for _, p := range ps.allFromArray() { - if p == nil { - continue - } - - if p.ArgFilter.Enabled() || - p.RetFilter.Enabled() || - p.ContextFilter.Enabled() || - (p.UIDFilter.Enabled() && ps.uidFilterableInUserland) || - (p.PIDFilter.Enabled() && ps.pidFilterableInUserland) { - // add policy and set the related bit - userlandList = append(userlandList, p) - utils.SetBit(&ps.filterableInUserland, uint(p.ID)) - } - } - - ps.userlandPolicies = userlandList -} - // set sets a policy at the given ID (index). func (ps *Policies) set(id int, p *Policy) error { p.ID = id @@ -261,25 +229,6 @@ func (ps *Policies) MatchedNames(matched uint64) []string { return names } -// allFromMap returns a map of allFromMap policies by ID. -// When iterating, the order is not guaranteed. -func (ps *Policies) allFromMap() map[int]*Policy { - return ps.policiesMapByID -} - -// allFromArray returns an slice of the underlying policies array. -// When iterating, the order is guaranteed. -func (ps *Policies) allFromArray() []*Policy { - return ps.policiesArray[:] -} - -// TODO: Runtime API should encapsulate the following calls: -// -// 1. pols := policies.Clone() to get a clone before to apply changes -// 2. policy.Snapshots().Store(pols) to get the new version snapshot stored -// 3. tracee.populateFilterMaps(pols, true) to update the maps -// 4. and possibly other steps in which we iterate over the policies map - // Clone returns a deep copy of Policies. func (ps *Policies) Clone() *Policies { if ps == nil { @@ -304,105 +253,16 @@ func (ps *Policies) Clone() *Policies { return nPols } -func (ps *Policies) updateContainerFilterEnabled() { - ps.containerFiltersEnabled = 0 - - for _, p := range ps.allFromMap() { - if p.ContainerFilterEnabled() { - utils.SetBit(&ps.containerFiltersEnabled, uint(p.ID)) - } - } +// allFromMap returns a map of allFromMap policies by ID. +// When iterating, the order is not guaranteed. +func (ps *Policies) allFromMap() map[int]*Policy { + return ps.policiesMapByID } -// calculateGlobalMinMax sets the global min and max, to be checked in kernel, -// of the Minimum and Maximum enabled filters only if context filter types -// (e.g. BPFUIDFilter) from all policies have both Minimum and Maximum values set. -// -// Policies userland filter flags are also set (e.g. uidFilterableInUserland). -// -// The context filter types relevant for this function are just UIDFilter and -// PIDFilter. -func (ps *Policies) calculateGlobalMinMax() { - var ( - uidMinFilterCount int - uidMaxFilterCount int - uidFilterCount int - pidMinFilterCount int - pidMaxFilterCount int - pidFilterCount int - policyCount int - - uidMinFilterableInUserland bool - uidMaxFilterableInUserland bool - pidMinFilterableInUserland bool - pidMaxFilterableInUserland bool - ) - - for _, p := range ps.allFromMap() { - policyCount++ - - if p.UIDFilter.Enabled() { - uidFilterCount++ - - if p.UIDFilter.Minimum() != filters.MinNotSetUInt { - uidMinFilterCount++ - } - if p.UIDFilter.Maximum() != filters.MaxNotSetUInt { - uidMaxFilterCount++ - } - } - if p.PIDFilter.Enabled() { - pidFilterCount++ - - if p.PIDFilter.Minimum() != filters.MinNotSetUInt { - pidMinFilterCount++ - } - if p.PIDFilter.Maximum() != filters.MaxNotSetUInt { - pidMaxFilterCount++ - } - } - } - - uidMinFilterableInUserland = policyCount > 1 && (uidMinFilterCount != uidFilterCount) - uidMaxFilterableInUserland = policyCount > 1 && (uidMaxFilterCount != uidFilterCount) - pidMinFilterableInUserland = policyCount > 1 && (pidMinFilterCount != pidFilterCount) - pidMaxFilterableInUserland = policyCount > 1 && (pidMaxFilterCount != pidFilterCount) - - // reset global min max - ps.uidFilterMax = filters.MaxNotSetUInt - ps.uidFilterMin = filters.MinNotSetUInt - ps.pidFilterMax = filters.MaxNotSetUInt - ps.pidFilterMin = filters.MinNotSetUInt - - ps.uidFilterableInUserland = uidMinFilterableInUserland || uidMaxFilterableInUserland - ps.pidFilterableInUserland = pidMinFilterableInUserland || pidMaxFilterableInUserland - - if ps.uidFilterableInUserland && ps.pidFilterableInUserland { - // there's no need to iterate filter policies again since - // all uint events will be submitted from ebpf with no regards - - return - } - - // set a reduced range of uint values to be filtered in ebpf - for _, p := range ps.allFromMap() { - if p.UIDFilter.Enabled() { - if !uidMinFilterableInUserland { - ps.uidFilterMin = utils.Min(ps.uidFilterMin, p.UIDFilter.Minimum()) - } - if !uidMaxFilterableInUserland { - ps.uidFilterMax = utils.Max(ps.uidFilterMax, p.UIDFilter.Maximum()) - } - } - if p.PIDFilter.Enabled() { - if !pidMinFilterableInUserland { - ps.pidFilterMin = utils.Min(ps.pidFilterMin, p.PIDFilter.Minimum()) - } - if !pidMaxFilterableInUserland { - ps.pidFilterMax = utils.Max(ps.pidFilterMax, p.PIDFilter.Maximum()) - } - } - } +// allFromArray returns an slice of the underlying policies array. +// When iterating, the order is guaranteed. +func (ps *Policies) allFromArray() []*Policy { + return ps.policiesArray[:] } func isIDInRange(id int) bool { diff --git a/pkg/policy/policies_compute.go b/pkg/policy/policies_compute.go new file mode 100644 index 000000000000..89e2fa31a741 --- /dev/null +++ b/pkg/policy/policies_compute.go @@ -0,0 +1,141 @@ +package policy + +import ( + "github.com/aquasecurity/tracee/pkg/filters" + "github.com/aquasecurity/tracee/pkg/utils" +) + +// compute recalculates values, updates flags, fills the reduced userland map, +// and sets the related bitmap that is used to prevent the iteration of the entire map. +// +// It must be called at every runtime policies changes. +func (ps *Policies) compute() { + ps.calculateGlobalMinMax() + ps.updateContainerFilterEnabled() + ps.updateUserlandPolicies() +} + +// calculateGlobalMinMax sets the global min and max, to be checked in kernel, +// of the Minimum and Maximum enabled filters only if context filter types +// (e.g. BPFUIDFilter) from all policies have both Minimum and Maximum values set. +// +// Policies userland filter flags are also set (e.g. uidFilterableInUserland). +// +// The context filter types relevant for this function are just UIDFilter and +// PIDFilter. +func (ps *Policies) calculateGlobalMinMax() { + var ( + uidMinFilterCount int + uidMaxFilterCount int + uidFilterCount int + pidMinFilterCount int + pidMaxFilterCount int + pidFilterCount int + policyCount int + + uidMinFilterableInUserland bool + uidMaxFilterableInUserland bool + pidMinFilterableInUserland bool + pidMaxFilterableInUserland bool + ) + + for _, p := range ps.allFromMap() { + policyCount++ + + if p.UIDFilter.Enabled() { + uidFilterCount++ + + if p.UIDFilter.Minimum() != filters.MinNotSetUInt { + uidMinFilterCount++ + } + if p.UIDFilter.Maximum() != filters.MaxNotSetUInt { + uidMaxFilterCount++ + } + } + if p.PIDFilter.Enabled() { + pidFilterCount++ + + if p.PIDFilter.Minimum() != filters.MinNotSetUInt { + pidMinFilterCount++ + } + if p.PIDFilter.Maximum() != filters.MaxNotSetUInt { + pidMaxFilterCount++ + } + } + } + + uidMinFilterableInUserland = policyCount > 1 && (uidMinFilterCount != uidFilterCount) + uidMaxFilterableInUserland = policyCount > 1 && (uidMaxFilterCount != uidFilterCount) + pidMinFilterableInUserland = policyCount > 1 && (pidMinFilterCount != pidFilterCount) + pidMaxFilterableInUserland = policyCount > 1 && (pidMaxFilterCount != pidFilterCount) + + // reset global min max + ps.uidFilterMax = filters.MaxNotSetUInt + ps.uidFilterMin = filters.MinNotSetUInt + ps.pidFilterMax = filters.MaxNotSetUInt + ps.pidFilterMin = filters.MinNotSetUInt + + ps.uidFilterableInUserland = uidMinFilterableInUserland || uidMaxFilterableInUserland + ps.pidFilterableInUserland = pidMinFilterableInUserland || pidMaxFilterableInUserland + + if ps.uidFilterableInUserland && ps.pidFilterableInUserland { + // there's no need to iterate filter policies again since + // all uint events will be submitted from ebpf with no regards + + return + } + + // set a reduced range of uint values to be filtered in ebpf + for _, p := range ps.allFromMap() { + if p.UIDFilter.Enabled() { + if !uidMinFilterableInUserland { + ps.uidFilterMin = utils.Min(ps.uidFilterMin, p.UIDFilter.Minimum()) + } + if !uidMaxFilterableInUserland { + ps.uidFilterMax = utils.Max(ps.uidFilterMax, p.UIDFilter.Maximum()) + } + } + if p.PIDFilter.Enabled() { + if !pidMinFilterableInUserland { + ps.pidFilterMin = utils.Min(ps.pidFilterMin, p.PIDFilter.Minimum()) + } + if !pidMaxFilterableInUserland { + ps.pidFilterMax = utils.Max(ps.pidFilterMax, p.PIDFilter.Maximum()) + } + } + } +} + +func (ps *Policies) updateContainerFilterEnabled() { + ps.containerFiltersEnabled = 0 + + for _, p := range ps.allFromMap() { + if p.ContainerFilterEnabled() { + utils.SetBit(&ps.containerFiltersEnabled, uint(p.ID)) + } + } +} + +// updateUserlandPolicies sets the userlandPolicies list and the filterableInUserland bitmap. +func (ps *Policies) updateUserlandPolicies() { + userlandList := []*Policy{} + ps.filterableInUserland = 0 + + for _, p := range ps.allFromArray() { + if p == nil { + continue + } + + if p.ArgFilter.Enabled() || + p.RetFilter.Enabled() || + p.ContextFilter.Enabled() || + (p.UIDFilter.Enabled() && ps.uidFilterableInUserland) || + (p.PIDFilter.Enabled() && ps.pidFilterableInUserland) { + // add policy to userland list and set the respective bit + userlandList = append(userlandList, p) + utils.SetBit(&ps.filterableInUserland, uint(p.ID)) + } + } + + ps.userlandPolicies = userlandList +}