From f07388cdc1c40a6fb9f37380b9637a4229827280 Mon Sep 17 00:00:00 2001 From: Raphael Campos Date: Wed, 22 May 2024 16:16:01 -0500 Subject: [PATCH] chore: rename args to data field Refactored the code in order to change the option args to name to be consistent with the new event structure. Option args is also supported but will be deprecated in future. --- cmd/tracee/cmd/root.go | 2 +- pkg/cmd/flags/event.go | 8 +- pkg/cmd/flags/filter.go | 12 +-- pkg/cmd/flags/policy.go | 10 ++- pkg/ebpf/events_pipeline.go | 2 +- pkg/ebpf/tracee.go | 8 +- pkg/events/derive/symbols_collision.go | 2 +- pkg/events/derive/symbols_loaded.go | 2 +- pkg/filters/{args.go => data.go} | 101 +++++++++++++------------ pkg/filters/errors.go | 4 +- pkg/policy/policies_compute.go | 2 +- pkg/policy/policy.go | 6 +- pkg/policy/v1beta1/policy_file.go | 25 +++--- 13 files changed, 94 insertions(+), 90 deletions(-) rename pkg/filters/{args.go => data.go} (57%) diff --git a/cmd/tracee/cmd/root.go b/cmd/tracee/cmd/root.go index 0931fc4e59ed..8aeefe27df83 100644 --- a/cmd/tracee/cmd/root.go +++ b/cmd/tracee/cmd/root.go @@ -103,7 +103,7 @@ func initCmd() error { "events", "e", []string{}, - "[name|name.args.pathname...]\tSelect events to trace and event filters", + "[name|name.data.pathname...]\tSelect events to trace and event filters", ) // policy is not bound to viper diff --git a/pkg/cmd/flags/event.go b/pkg/cmd/flags/event.go index c0ce9115cf99..b1343c24c481 100644 --- a/pkg/cmd/flags/event.go +++ b/pkg/cmd/flags/event.go @@ -135,15 +135,15 @@ func parseEventFlag(flag string) ([]eventFlag, error) { return []eventFlag{ { - full: flag, // "openat.args.pathname=/etc/*" - eventFilter: evtFilter, // "openat.args.pathname" + full: flag, // "openat.data.pathname=/etc/*" + eventFilter: evtFilter, // "openat.data.pathname" eventName: evtParts.name, // "openat" - eventOptionType: evtParts.optType, // "args" + eventOptionType: evtParts.optType, // "data" eventOptionName: evtParts.optName, // "pathname" operator: opAndValParts.operator, // "=" values: opAndValParts.values, // "/etc/*" operatorAndValues: opAndValParts.operatorAndValues, // "=/etc/*" - filter: filter, // "args.pathname=/etc/*" + filter: filter, // "data.pathname=/etc/*" }, }, nil } diff --git a/pkg/cmd/flags/filter.go b/pkg/cmd/flags/filter.go index f29aa46dbb0c..7f26958110fb 100644 --- a/pkg/cmd/flags/filter.go +++ b/pkg/cmd/flags/filter.go @@ -24,8 +24,8 @@ Available boolean expressions: container. Event flag selects events or sets of events to trace according to predefined sets, which can be listed by using the 'list' flag. Event flag uses a dash prefix to filter out events: '-'. -Event arguments can be accessed using 'event_name.args.event_arg' and provide a way to filter an event by its arguments. -Event arguments allow the following operators: '=', '!='. +Event data can be accessed using 'event_name.data.event_arg' and provide a way to filter an event by its data. +Event data allow the following operators: '=', '!='. Strings can be compared as a prefix if ending with '*' or as suffix if starting with '*'. Event return value can be accessed using 'event_name.retval' and provide a way to filter an event by its return value. @@ -77,10 +77,10 @@ Event examples: --events '-open*,-dup*' | don't trace events prefixed by "open" or "dup" --events fs | trace all file-system related events --events fs --events -open,-openat | trace all file-system related events, but not open(at) - --events close.args.fd=5 | only trace 'close' events that have 'fd' equals 5 - --events openat.args.pathname='/tmp*' | only trace 'openat' events that have 'pathname' prefixed by /tmp - --events openat.args.pathname='*shadow' | only trace 'openat' events that have 'pathname' suffixed by shadow - --events openat.args.pathname!=/tmp/1,/bin/ls | don't trace 'openat' events that have 'pathname' equals /tmp/1 or /bin/ls + --events close.data.fd=5 | only trace 'close' events that have 'fd' equals 5 + --events openat.data.pathname='/tmp*' | only trace 'openat' events that have 'pathname' prefixed by /tmp + --events openat.data.pathname='*shadow' | only trace 'openat' events that have 'pathname' suffixed by shadow + --events openat.data.pathname!=/tmp/1,/bin/ls | don't trace 'openat' events that have 'pathname' equals /tmp/1 or /bin/ls --events openat.scope.processName=ls | only trace 'openat' events that have 'processName' equal to 'ls' --events security_file_open.scope.container | only trace 'security_file_open' events coming from a container diff --git a/pkg/cmd/flags/policy.go b/pkg/cmd/flags/policy.go index 761f75a195e9..55e9d09517fd 100644 --- a/pkg/cmd/flags/policy.go +++ b/pkg/cmd/flags/policy.go @@ -70,8 +70,10 @@ func PrepareFilterMapsFromPolicies(policies []k8s.PolicyInterface) (PolicyScopeM eventFlags = append(eventFlags, evtFlags...) for _, f := range r.Filters { - // event argument or return value filter - if strings.HasPrefix(f, "args.") || strings.HasPrefix(f, "retval") { + // event data or return value filter + // option "args." will be deprecate in future + if strings.HasPrefix(f, "data.") || strings.HasPrefix(f, "args.") || + strings.HasPrefix(f, "retval") { evtFilterFlags, err := parseEventFlag(fmt.Sprintf("%s.%s", r.Event, f)) if err != nil { return nil, nil, errfmt.WrapError(err) @@ -297,8 +299,8 @@ func CreatePolicies(policyScopeMap PolicyScopeMap, policyEventsMap PolicyEventMa continue } - if evtFlag.eventOptionType == "args" { - err := p.ArgFilter.Parse(evtFilter, operatorAndValues, eventsNameToID) + if evtFlag.eventOptionType == "data" || evtFlag.eventOptionType == "args" { + err := p.DataFilter.Parse(evtFilter, operatorAndValues, eventsNameToID) if err != nil { return nil, err } diff --git a/pkg/ebpf/events_pipeline.go b/pkg/ebpf/events_pipeline.go index 062511d9d187..cfad4f6e5a31 100644 --- a/pkg/ebpf/events_pipeline.go +++ b/pkg/ebpf/events_pipeline.go @@ -342,7 +342,7 @@ func (t *Tracee) matchPolicies(event *trace.Event) uint64 { } // 3. event arguments filters - if !p.ArgFilter.Filter(eventID, event.Args) { + if !p.DataFilter.Filter(eventID, event.Args) { utils.ClearBit(&bitmap, bitOffset) continue } diff --git a/pkg/ebpf/tracee.go b/pkg/ebpf/tracee.go index 0651f2f5846a..968d372e803a 100644 --- a/pkg/ebpf/tracee.go +++ b/pkg/ebpf/tracee.go @@ -1620,12 +1620,12 @@ func (t *Tracee) triggerMemDump(event trace.Event) []error { if !isChosen { continue } - printMemDumpFilters := p.ArgFilter.GetEventFilters(events.PrintMemDump) + printMemDumpFilters := p.DataFilter.GetEventFilters(events.PrintMemDump) if len(printMemDumpFilters) == 0 { errs = append(errs, errfmt.Errorf("policy %d: no address or symbols were provided to print_mem_dump event. "+ - "please provide it via -e print_mem_dump.args.address="+ - ", -e print_mem_dump.args.symbol_name=: or "+ - "-e print_mem_dump.args.symbol_name= if specifying a system owned symbol", p.ID)) + "please provide it via -e print_mem_dump.data.address="+ + ", -e print_mem_dump.data.symbol_name=: or "+ + "-e print_mem_dump.data.symbol_name= if specifying a system owned symbol", p.ID)) continue } diff --git a/pkg/events/derive/symbols_collision.go b/pkg/events/derive/symbols_collision.go index c21740cc2818..aab3253f94fa 100644 --- a/pkg/events/derive/symbols_collision.go +++ b/pkg/events/derive/symbols_collision.go @@ -33,7 +33,7 @@ func SymbolsCollision(soLoader sharedobjs.DynamicSymbolsLoader, policies *policy // pick white and black lists from the filters (TODO: change this) for it := policies.CreateAllIterator(); it.HasNext(); { p := it.Next() - f := p.ArgFilter.GetEventFilters(events.SymbolsCollision) + f := p.DataFilter.GetEventFilters(events.SymbolsCollision) maps.Copy(symbolsCollisionFilters, f) } diff --git a/pkg/events/derive/symbols_loaded.go b/pkg/events/derive/symbols_loaded.go index 2a11e4054c57..7547e9c451a4 100644 --- a/pkg/events/derive/symbols_loaded.go +++ b/pkg/events/derive/symbols_loaded.go @@ -26,7 +26,7 @@ func SymbolsLoaded( for it := policies.CreateAllIterator(); it.HasNext(); { p := it.Next() - f := p.ArgFilter.GetEventFilters(events.SymbolsLoaded) + f := p.DataFilter.GetEventFilters(events.SymbolsLoaded) maps.Copy(symbolsLoadedFilters, f) } diff --git a/pkg/filters/args.go b/pkg/filters/data.go similarity index 57% rename from pkg/filters/args.go rename to pkg/filters/data.go index dcc72acac958..2a54620245cf 100644 --- a/pkg/filters/args.go +++ b/pkg/filters/data.go @@ -11,28 +11,28 @@ import ( "github.com/aquasecurity/tracee/types/trace" ) -type ArgFilter struct { +type DataFilter struct { filters map[events.ID]map[string]Filter[*StringFilter] enabled bool } -// Compile-time check to ensure that ArgFilter implements the Cloner interface -var _ utils.Cloner[*ArgFilter] = &ArgFilter{} +// Compile-time check to ensure that DataFilter implements the Cloner interface +var _ utils.Cloner[*DataFilter] = &DataFilter{} -func NewArgFilter() *ArgFilter { - return &ArgFilter{ +func NewDataFilter() *DataFilter { + return &DataFilter{ filters: map[events.ID]map[string]Filter[*StringFilter]{}, enabled: false, } } -// GetEventFilters returns the argument filters map for a specific event +// GetEventFilters returns the data filters map for a specific event // writing to the map may have unintentional consequences, avoid doing so -func (af *ArgFilter) GetEventFilters(eventID events.ID) map[string]Filter[*StringFilter] { +func (af *DataFilter) GetEventFilters(eventID events.ID) map[string]Filter[*StringFilter] { return af.filters[eventID] } -func (af *ArgFilter) Filter(eventID events.ID, args []trace.Argument) bool { +func (af *DataFilter) Filter(eventID events.ID, data []trace.Argument) bool { if !af.Enabled() { return true } @@ -46,14 +46,14 @@ func (af *ArgFilter) Filter(eventID events.ID, args []trace.Argument) bool { return true } - for argName, f := range af.filters[eventID] { + for dataName, f := range af.filters[eventID] { found := false - var argVal interface{} + var dataVal interface{} - for _, arg := range args { - if arg.Name == argName { + for _, d := range data { + if d.Name == dataName { found = true - argVal = arg.Value + dataVal = d.Value break } } @@ -62,9 +62,9 @@ func (af *ArgFilter) Filter(eventID events.ID, args []trace.Argument) bool { } // TODO: use type assertion instead of string conversion - argVal = fmt.Sprint(argVal) + dataVal = fmt.Sprint(dataVal) - res := f.Filter(argVal) + res := f.Filter(dataVal) if !res { return false } @@ -73,21 +73,22 @@ func (af *ArgFilter) Filter(eventID events.ID, args []trace.Argument) bool { return true } -func (af *ArgFilter) Parse(filterName string, operatorAndValues string, eventsNameToID map[string]events.ID) error { - // Event argument filter has the following format: "event.args.argname=argval" - // filterName have the format event.argname, and operatorAndValues have the format "=argval" +func (af *DataFilter) Parse(filterName string, operatorAndValues string, eventsNameToID map[string]events.ID) error { + // Event data filter has the following format: "event.data.dataname=dataval" + // filterName have the format event.dataname, and operatorAndValues have the format "=dataval" parts := strings.Split(filterName, ".") if len(parts) != 3 { return InvalidExpression(filterName + operatorAndValues) } - if parts[1] != "args" { + // option "args" will be deprecate in future + if (parts[1] != "data") && (parts[1] != "args") { return InvalidExpression(filterName + operatorAndValues) } eventName := parts[0] - argName := parts[2] + dataName := parts[2] - if eventName == "" || argName == "" { + if eventName == "" || dataName == "" { return InvalidExpression(filterName + operatorAndValues) } @@ -102,18 +103,18 @@ func (af *ArgFilter) Parse(filterName string, operatorAndValues string, eventsNa eventDefinition := events.Core.GetDefinitionByID(id) eventParams := eventDefinition.GetParams() - // check if argument name exists for this event - argFound := false + // check if data name exists for this event + dataFound := false for i := range eventParams { - if eventParams[i].Name == argName { - argFound = true + if eventParams[i].Name == dataName { + dataFound = true break } } // if the event is a signature event, we allow filtering on dynamic argument - if !argFound && !eventDefinition.IsSignature() { - return InvalidEventArgument(argName) + if !dataFound && !eventDefinition.IsSignature() { + return InvalidEventData(dataName) } // valueHandler is passed to the filter constructor to allow for custom value handling @@ -122,7 +123,7 @@ func (af *ArgFilter) Parse(filterName string, operatorAndValues string, eventsNa switch id { case events.SysEnter, events.SysExit: - if argName == "syscall" { // handle either syscall name or syscall id + if dataName == "syscall" { // handle either syscall name or syscall id _, err := strconv.Atoi(val) if err != nil { // if val is a syscall name, then we need to convert it to a syscall id @@ -134,11 +135,11 @@ func (af *ArgFilter) Parse(filterName string, operatorAndValues string, eventsNa } } case events.HookedSyscall: - if argName == "syscall" { // handle either syscall name or syscall id - argEventID, err := strconv.Atoi(val) + if dataName == "syscall" { // handle either syscall name or syscall id + dataEventID, err := strconv.Atoi(val) if err == nil { // if val is a syscall id, then we need to convert it to a syscall name - val = events.Core.GetDefinitionByID(events.ID(argEventID)).GetName() + val = events.Core.GetDefinitionByID(events.ID(dataEventID)).GetName() } } } @@ -146,9 +147,9 @@ func (af *ArgFilter) Parse(filterName string, operatorAndValues string, eventsNa return val, nil } - err := af.parseFilter(id, argName, operatorAndValues, + err := af.parseFilter(id, dataName, operatorAndValues, func() Filter[*StringFilter] { - // TODO: map argument type to an appropriate filter constructor + // TODO: map data type to an appropriate filter constructor return NewStringFilter(valueHandler) }) if err != nil { @@ -160,33 +161,33 @@ func (af *ArgFilter) Parse(filterName string, operatorAndValues string, eventsNa return nil } -// parseFilter adds an argument filter with the relevant filterConstructor +// parseFilter adds an data filter with the relevant filterConstructor // The user must responsibly supply a reliable Filter object. -func (af *ArgFilter) parseFilter(id events.ID, argName string, operatorAndValues string, filterConstructor func() Filter[*StringFilter]) error { +func (af *DataFilter) parseFilter(id events.ID, dataName string, operatorAndValues string, filterConstructor func() Filter[*StringFilter]) error { if _, ok := af.filters[id]; !ok { af.filters[id] = map[string]Filter[*StringFilter]{} } - if _, ok := af.filters[id][argName]; !ok { - // store new event arg filter if missing - argFilter := filterConstructor() - af.filters[id][argName] = argFilter + if _, ok := af.filters[id][dataName]; !ok { + // store new event data filter if missing + dataFilter := filterConstructor() + af.filters[id][dataName] = dataFilter } - // extract the arg filter and parse expression into it - f := af.filters[id][argName] + // extract the data filter and parse expression into it + f := af.filters[id][dataName] err := f.Parse(operatorAndValues) if err != nil { return errfmt.WrapError(err) } - // store the arg filter again - af.filters[id][argName] = f + // store the data filter again + af.filters[id][dataName] = f return nil } -func (af *ArgFilter) Enable() { +func (af *DataFilter) Enable() { af.enabled = true for _, filterMap := range af.filters { for _, f := range filterMap { @@ -195,7 +196,7 @@ func (af *ArgFilter) Enable() { } } -func (af *ArgFilter) Disable() { +func (af *DataFilter) Disable() { af.enabled = false for _, filterMap := range af.filters { for _, f := range filterMap { @@ -204,21 +205,21 @@ func (af *ArgFilter) Disable() { } } -func (af *ArgFilter) Enabled() bool { +func (af *DataFilter) Enabled() bool { return af.enabled } -func (af *ArgFilter) Clone() *ArgFilter { +func (af *DataFilter) Clone() *DataFilter { if af == nil { return nil } - n := NewArgFilter() + n := NewDataFilter() for eventID, filterMap := range af.filters { n.filters[eventID] = map[string]Filter[*StringFilter]{} - for argName, f := range filterMap { - n.filters[eventID][argName] = f.Clone() + for dataName, f := range filterMap { + n.filters[eventID][dataName] = f.Clone() } } diff --git a/pkg/filters/errors.go b/pkg/filters/errors.go index 43ced93908d4..a151a4cd263b 100644 --- a/pkg/filters/errors.go +++ b/pkg/filters/errors.go @@ -24,8 +24,8 @@ func InvalidEventName(event string) error { return fmt.Errorf("invalid event name in filter: %s", event) } -func InvalidEventArgument(argument string) error { - return fmt.Errorf("invalid filter event argument: %s", argument) +func InvalidEventData(data string) error { + return fmt.Errorf("invalid filter event data: %s", data) } func InvalidScopeField(field string) error { diff --git a/pkg/policy/policies_compute.go b/pkg/policy/policies_compute.go index 13af7d6aa995..16e503990e79 100644 --- a/pkg/policy/policies_compute.go +++ b/pkg/policy/policies_compute.go @@ -126,7 +126,7 @@ func (ps *Policies) updateUserlandPolicies() { continue } - if p.ArgFilter.Enabled() || + if p.DataFilter.Enabled() || p.RetFilter.Enabled() || p.ScopeFilter.Enabled() || (p.UIDFilter.Enabled() && ps.uidFilterableInUserland) || diff --git a/pkg/policy/policy.go b/pkg/policy/policy.go index 703030e2f011..541170b75104 100644 --- a/pkg/policy/policy.go +++ b/pkg/policy/policy.go @@ -23,7 +23,7 @@ type Policy struct { NewContFilter *filters.BoolFilter ContIDFilter *filters.StringFilter RetFilter *filters.RetFilter - ArgFilter *filters.ArgFilter + DataFilter *filters.DataFilter ScopeFilter *filters.ScopeFilter ProcessTreeFilter *filters.ProcessTreeFilter BinaryFilter *filters.BinaryFilter @@ -49,7 +49,7 @@ func NewPolicy() *Policy { NewContFilter: filters.NewBoolFilter(), ContIDFilter: filters.NewStringFilter(nil), RetFilter: filters.NewRetFilter(), - ArgFilter: filters.NewArgFilter(), + DataFilter: filters.NewDataFilter(), ScopeFilter: filters.NewScopeFilter(), ProcessTreeFilter: filters.NewProcessTreeFilter(), BinaryFilter: filters.NewBinaryFilter(), @@ -85,7 +85,7 @@ func (p *Policy) Clone() *Policy { n.NewContFilter = p.NewContFilter.Clone() n.ContIDFilter = p.ContIDFilter.Clone() n.RetFilter = p.RetFilter.Clone() - n.ArgFilter = p.ArgFilter.Clone() + n.DataFilter = p.DataFilter.Clone() n.ScopeFilter = p.ScopeFilter.Clone() n.ProcessTreeFilter = p.ProcessTreeFilter.Clone() n.BinaryFilter = p.BinaryFilter.Clone() diff --git a/pkg/policy/v1beta1/policy_file.go b/pkg/policy/v1beta1/policy_file.go index 361fbd6679dd..027072045e40 100644 --- a/pkg/policy/v1beta1/policy_file.go +++ b/pkg/policy/v1beta1/policy_file.go @@ -200,14 +200,15 @@ func (p PolicyFile) validateRules() error { return errfmt.Errorf("policy %s, invalid filter operator: %s", p.GetName(), f) } - // args - if strings.HasPrefix(f, "args") { + // data + // option "args" will be deprecate in future + if strings.HasPrefix(f, "data") || strings.HasPrefix(f, "args") { s := strings.Split(f, ".") if len(s) == 1 { - return errfmt.Errorf("policy %s, arg name can't be empty", p.GetName()) + return errfmt.Errorf("policy %s, data name can't be empty", p.GetName()) } - err := validateEventArg(p.GetName(), r.Event, s[1]) + err := validateEventData(p.GetName(), r.Event, s[1]) if err != nil { return err } @@ -251,22 +252,22 @@ func validateEvent(policyName, eventName string) error { return nil } -func validateEventArg(policyName, eventName, argName string) error { - s := strings.Split(argName, "!=") +func validateEventData(policyName, eventName, dataName string) error { + s := strings.Split(dataName, "!=") if len(s) == 1 { - s = strings.Split(argName, "=") + s = strings.Split(dataName, "=") } if len(s) == 1 { - return errfmt.Errorf("policy %s, arg %s value can't be empty", policyName, s[0]) + return errfmt.Errorf("policy %s, data %s value can't be empty", policyName, s[0]) } if s[1] == "" { - return errfmt.Errorf("policy %s, arg %s value can't be empty", policyName, s[0]) + return errfmt.Errorf("policy %s, data %s value can't be empty", policyName, s[0]) } - argName = s[0] + dataName = s[0] eventDefID, ok := events.Core.GetDefinitionIDByName(eventName) if !ok { @@ -281,12 +282,12 @@ func validateEventArg(policyName, eventName, argName string) error { } } for _, p := range eventDefinition.GetParams() { - if p.Name == argName { + if p.Name == dataName { return nil } } - return errfmt.Errorf("policy %s, event %s does not have argument %s", policyName, eventName, argName) + return errfmt.Errorf("policy %s, event %s does not have data %s", policyName, eventName, dataName) } // PoliciesFromPaths returns a slice of policies from the given paths