tetragon
1// SPDX-License-Identifier: Apache-2.0
2// Copyright Authors of Cilium
3
4package filters5
6import (7"context"8
9v1 "github.com/cilium/cilium/pkg/hubble/api/v1"10hubbleFilters "github.com/cilium/cilium/pkg/hubble/filters"11"github.com/cilium/tetragon/api/v1/tetragon"12"github.com/cilium/tetragon/pkg/logger"13)
14
15// We could use an LRU here but we really don't want to evict old entries and risk failing
16// a test that uses this filter. Instead, we take the safer approach from the perspective
17// of testing and opt to grow the map indefinitely and log a warning if the size exceeeds
18// a pre-determined threshold. Since we have protections in place to prevent this filter
19// being used in production, this should be acceptable.
20type ChildCache = map[uint32]struct{}21
22func checkPidSetMembership(pid uint32, pidSet []uint32, childCache ChildCache) bool {23// Check the original pidSet. The reason for doing this separately is that we never24// want to drop the original pidSet from the cache. Keeping this separately in a slice25// is an easy way to achieve this.26for _, p := range pidSet {27if pid == p {28return true29}30}31// Fall back to childCache to check children.32_, ok := childCache[pid]33return ok34}
35
36func doFilterByPidSet(ev *v1.Event, pidSet []uint32, childCache ChildCache, childCacheWarning *int) bool {37process := GetProcess(ev)38if process == nil {39return false40}41
42// Check the process against our cache43pid := process.Pid.GetValue()44if checkPidSetMembership(pid, pidSet, childCache) {45return true46}47
48parent := GetParent(ev)49if parent == nil {50return false51}52
53// Check the parent against our cache54ppid := parent.Pid.GetValue()55if checkPidSetMembership(ppid, pidSet, childCache) {56// Add our own PID to the children cache so that we can match our future children.57childCache[pid] = struct{}{}58// If we exceeded the pre-determined warning limit, log a warning message and59// double it.60if len(childCache) == *childCacheWarning {61logger.GetLogger().Warnf("pidSet filter cache has exceeded %d entries. To prevent excess memory usage, consider disabling it.", childCacheWarning)62*childCacheWarning *= 263}64return true65}66
67// No matches, return false68return false69}
70
71func filterByPidSet(pidSet []uint32, childCache ChildCache, childCacheWarning int) hubbleFilters.FilterFunc {72return func(ev *v1.Event) bool {73return doFilterByPidSet(ev, pidSet, childCache, &childCacheWarning)74}75}
76
77// PidSetFilter is a filter that matches on a process and all of its children by their
78// PID, up to maxChildCacheSize number of children.
79type PidSetFilter struct{}80
81func (f *PidSetFilter) OnBuildFilter(_ context.Context, ff *tetragon.Filter) ([]hubbleFilters.FilterFunc, error) {82var fs []hubbleFilters.FilterFunc83if ff.PidSet != nil {84childCache := make(ChildCache)85childCacheWarning := 819286
87pidSet := ff.PidSet88fs = append(fs, filterByPidSet(pidSet, childCache, childCacheWarning))89}90return fs, nil91}
92