github.com/DataDog/datadog-agent/pkg/security/secl@v0.55.0-devel.0.20240517055856-10c4965fea94/rules/approvers.go (about) 1 // Unless explicitly stated otherwise all files in this repository are licensed 2 // under the Apache License Version 2.0. 3 // This product includes software developed at Datadog (https://www.datadoghq.com/). 4 // Copyright 2016-present Datadog, Inc. 5 6 // Package rules holds rules related files 7 package rules 8 9 import ( 10 "errors" 11 12 "github.com/DataDog/datadog-agent/pkg/security/secl/compiler/eval" 13 ) 14 15 // Approvers are just filter values indexed by field 16 type Approvers map[eval.Field]FilterValues 17 18 // isAnApprover returns whether the given value is an approver for the given rule 19 func isAnApprover(event eval.Event, ctx *eval.Context, rule *Rule, field eval.Field, value interface{}) (bool, error) { 20 var readOnlyError *eval.ErrFieldReadOnly 21 if err := event.SetFieldValue(field, value); err != nil { 22 if errors.As(err, &readOnlyError) { 23 return false, nil 24 } 25 return false, err 26 } 27 origResult, err := rule.PartialEval(ctx, field) 28 if err != nil { 29 return false, err 30 } 31 32 notValue, err := eval.NotOfValue(value) 33 if err != nil { 34 return false, err 35 } 36 37 if err := event.SetFieldValue(field, notValue); err != nil { 38 if errors.As(err, &readOnlyError) { 39 return false, nil 40 } 41 return false, err 42 } 43 notResult, err := rule.PartialEval(ctx, field) 44 if err != nil { 45 return false, err 46 } 47 48 return origResult && !notResult, nil 49 } 50 51 func bitmaskCombinations(bitmasks []int) []int { 52 if len(bitmasks) == 0 { 53 return nil 54 } 55 56 combinationCount := 1 << len(bitmasks) 57 result := make([]int, 0, combinationCount) 58 for i := 0; i < combinationCount; i++ { 59 var mask int 60 for j, value := range bitmasks { 61 if (i & (1 << j)) > 0 { 62 mask |= value 63 } 64 } 65 result = append(result, mask) 66 } 67 68 return result 69 } 70 71 // GetApprovers returns approvers for the given rules 72 func GetApprovers(rules []*Rule, event eval.Event, fieldCaps FieldCapabilities) (Approvers, error) { 73 approvers := make(Approvers) 74 75 ctx := eval.NewContext(event) 76 77 // for each rule we should at least find one approver otherwise we will return no approver for the field 78 for _, rule := range rules { 79 var bestFilterField eval.Field 80 var bestFilterValues FilterValues 81 var bestFilterWeight int 82 83 LOOP: 84 for _, fieldCap := range fieldCaps { 85 field := fieldCap.Field 86 87 var filterValues FilterValues 88 var bitmasks []int 89 90 for _, value := range rule.GetFieldValues(field) { 91 switch value.Type { 92 case eval.ScalarValueType, eval.PatternValueType, eval.GlobValueType: 93 isAnApprover, err := isAnApprover(event, ctx, rule, field, value.Value) 94 if err != nil { 95 return nil, err 96 } 97 98 if isAnApprover { 99 filterValues = filterValues.Merge(FilterValue{Field: field, Value: value.Value, Type: value.Type}) 100 } else if fieldCap.Types&eval.BitmaskValueType == 0 { 101 // if not a bitmask we need to have all the value as approvers 102 // basically a list of values ex: in ["test123", "test456"] 103 continue LOOP 104 } 105 case eval.BitmaskValueType: 106 bitmasks = append(bitmasks, value.Value.(int)) 107 } 108 } 109 110 for _, bitmask := range bitmaskCombinations(bitmasks) { 111 isAnApprover, err := isAnApprover(event, ctx, rule, field, bitmask) 112 if err != nil { 113 return nil, err 114 } 115 116 if isAnApprover { 117 filterValues = filterValues.Merge(FilterValue{Field: field, Value: bitmask, Type: eval.BitmaskValueType}) 118 } 119 } 120 121 if len(filterValues) == 0 || !fieldCaps.Validate(filterValues) { 122 continue 123 } 124 125 if bestFilterValues == nil || fieldCap.FilterWeight > bestFilterWeight { 126 bestFilterField = field 127 bestFilterValues = filterValues 128 bestFilterWeight = fieldCap.FilterWeight 129 } 130 } 131 132 // no filter value for a rule thus no approver for the event type 133 if bestFilterValues == nil { 134 return nil, nil 135 } 136 137 approvers[bestFilterField] = append(approvers[bestFilterField], bestFilterValues...) 138 } 139 140 return approvers, nil 141 }