github.com/DataDog/datadog-agent/pkg/security/secl@v0.55.0-devel.0.20240517055856-10c4965fea94/compiler/eval/variables.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 eval holds eval related files 7 package eval 8 9 import ( 10 "errors" 11 "fmt" 12 "reflect" 13 "regexp" 14 ) 15 16 var ( 17 variableRegex = regexp.MustCompile(`\${[^}]*}`) 18 errAppendNotSupported = errors.New("append is not supported") 19 ) 20 21 // VariableValue describes a SECL variable value 22 type VariableValue interface { 23 GetEvaluator() interface{} 24 } 25 26 // MutableVariable is the interface implemented by modifiable variables 27 type MutableVariable interface { 28 Set(ctx *Context, value interface{}) error 29 Append(ctx *Context, value interface{}) error 30 } 31 32 // Variable describes a SECL variable 33 type Variable struct { 34 setFnc func(ctx *Context, value interface{}) error 35 } 36 37 // Set the variable with the specified value 38 func (v *Variable) Set(ctx *Context, value interface{}) error { 39 if v.setFnc == nil { 40 return errors.New("variable is not mutable") 41 } 42 43 return v.setFnc(ctx, value) 44 } 45 46 // Append a value to the variable 47 func (v *Variable) Append(_ *Context, _ interface{}) error { 48 return errAppendNotSupported 49 } 50 51 // IntVariable describes an integer variable 52 type IntVariable struct { 53 Variable 54 intFnc func(ctx *Context) int 55 } 56 57 // GetEvaluator returns the variable SECL evaluator 58 func (i *IntVariable) GetEvaluator() interface{} { 59 return &IntEvaluator{ 60 EvalFnc: func(ctx *Context) int { 61 return i.intFnc(ctx) 62 }, 63 } 64 } 65 66 // NewIntVariable returns a new integer variable 67 func NewIntVariable(intFnc func(ctx *Context) int, setFnc func(ctx *Context, value interface{}) error) *IntVariable { 68 return &IntVariable{ 69 Variable: Variable{ 70 setFnc: setFnc, 71 }, 72 intFnc: intFnc, 73 } 74 } 75 76 // StringVariable describes a string variable 77 type StringVariable struct { 78 Variable 79 strFnc func(ctx *Context) string 80 } 81 82 // GetEvaluator returns the variable SECL evaluator 83 func (s *StringVariable) GetEvaluator() interface{} { 84 return &StringEvaluator{ 85 ValueType: VariableValueType, 86 EvalFnc: func(ctx *Context) string { 87 return s.strFnc(ctx) 88 }, 89 } 90 } 91 92 // NewStringVariable returns a new string variable 93 func NewStringVariable(strFnc func(ctx *Context) string, setFnc func(ctx *Context, value interface{}) error) *StringVariable { 94 return &StringVariable{ 95 strFnc: strFnc, 96 Variable: Variable{ 97 setFnc: setFnc, 98 }, 99 } 100 } 101 102 // BoolVariable describes a boolean variable 103 type BoolVariable struct { 104 Variable 105 boolFnc func(ctx *Context) bool 106 } 107 108 // GetEvaluator returns the variable SECL evaluator 109 func (b *BoolVariable) GetEvaluator() interface{} { 110 return &BoolEvaluator{ 111 EvalFnc: func(ctx *Context) bool { 112 return b.boolFnc(ctx) 113 }, 114 } 115 } 116 117 // NewBoolVariable returns a new boolean variable 118 func NewBoolVariable(boolFnc func(ctx *Context) bool, setFnc func(ctx *Context, value interface{}) error) *BoolVariable { 119 return &BoolVariable{ 120 boolFnc: boolFnc, 121 Variable: Variable{ 122 setFnc: setFnc, 123 }, 124 } 125 } 126 127 // StringArrayVariable describes a string array variable 128 type StringArrayVariable struct { 129 Variable 130 strFnc func(ctx *Context) []string 131 } 132 133 // GetEvaluator returns the variable SECL evaluator 134 func (s *StringArrayVariable) GetEvaluator() interface{} { 135 return &StringArrayEvaluator{ 136 EvalFnc: s.strFnc, 137 } 138 } 139 140 // Set the array values 141 func (s *StringArrayVariable) Set(ctx *Context, value interface{}) error { 142 if s, ok := value.(string); ok { 143 value = []string{s} 144 } 145 return s.Variable.Set(ctx, value) 146 } 147 148 // Append a value to the array 149 func (s *StringArrayVariable) Append(ctx *Context, value interface{}) error { 150 return s.Set(ctx, append(s.strFnc(ctx), value.([]string)...)) 151 } 152 153 // NewStringArrayVariable returns a new string array variable 154 func NewStringArrayVariable(strFnc func(ctx *Context) []string, setFnc func(ctx *Context, value interface{}) error) *StringArrayVariable { 155 return &StringArrayVariable{ 156 strFnc: strFnc, 157 Variable: Variable{ 158 setFnc: setFnc, 159 }, 160 } 161 } 162 163 // IntArrayVariable describes an integer array variable 164 type IntArrayVariable struct { 165 Variable 166 intFnc func(ctx *Context) []int 167 } 168 169 // GetEvaluator returns the variable SECL evaluator 170 func (s *IntArrayVariable) GetEvaluator() interface{} { 171 return &IntArrayEvaluator{ 172 EvalFnc: s.intFnc, 173 } 174 } 175 176 // Set the array values 177 func (s *IntArrayVariable) Set(ctx *Context, value interface{}) error { 178 if i, ok := value.(int); ok { 179 value = []int{i} 180 } 181 return s.Variable.Set(ctx, value) 182 } 183 184 // Append a value to the array 185 func (s *IntArrayVariable) Append(ctx *Context, value interface{}) error { 186 return s.Set(ctx, append(s.intFnc(ctx), value.([]int)...)) 187 } 188 189 // NewIntArrayVariable returns a new integer array variable 190 func NewIntArrayVariable(intFnc func(ctx *Context) []int, setFnc func(ctx *Context, value interface{}) error) *IntArrayVariable { 191 return &IntArrayVariable{ 192 intFnc: intFnc, 193 Variable: Variable{ 194 setFnc: setFnc, 195 }, 196 } 197 } 198 199 // MutableIntVariable describes a mutable integer variable 200 type MutableIntVariable struct { 201 Value int 202 } 203 204 // Set the variable with the specified value 205 func (m *MutableIntVariable) Set(_ *Context, value interface{}) error { 206 m.Value = value.(int) 207 return nil 208 } 209 210 // Append a value to the integer 211 func (m *MutableIntVariable) Append(_ *Context, value interface{}) error { 212 switch value := value.(type) { 213 case int: 214 m.Value += value 215 default: 216 return errAppendNotSupported 217 } 218 return nil 219 } 220 221 // GetEvaluator returns the variable SECL evaluator 222 func (m *MutableIntVariable) GetEvaluator() interface{} { 223 return &IntEvaluator{ 224 EvalFnc: func(ctx *Context) int { 225 return m.Value 226 }, 227 } 228 } 229 230 // NewMutableIntVariable returns a new mutable integer variable 231 func NewMutableIntVariable() *MutableIntVariable { 232 return &MutableIntVariable{} 233 } 234 235 // MutableBoolVariable describes a mutable boolean variable 236 type MutableBoolVariable struct { 237 Value bool 238 } 239 240 // GetEvaluator returns the variable SECL evaluator 241 func (m *MutableBoolVariable) GetEvaluator() interface{} { 242 return &BoolEvaluator{ 243 EvalFnc: func(ctx *Context) bool { 244 return m.Value 245 }, 246 } 247 } 248 249 // Set the variable with the specified value 250 func (m *MutableBoolVariable) Set(_ *Context, value interface{}) error { 251 m.Value = value.(bool) 252 return nil 253 } 254 255 // Append a value to the boolean 256 func (m *MutableBoolVariable) Append(_ *Context, _ interface{}) error { 257 return errAppendNotSupported 258 } 259 260 // NewMutableBoolVariable returns a new mutable boolean variable 261 func NewMutableBoolVariable() *MutableBoolVariable { 262 return &MutableBoolVariable{} 263 } 264 265 // MutableStringVariable describes a mutable string variable 266 type MutableStringVariable struct { 267 Value string 268 } 269 270 // GetEvaluator returns the variable SECL evaluator 271 func (m *MutableStringVariable) GetEvaluator() interface{} { 272 return &StringEvaluator{ 273 ValueType: VariableValueType, 274 EvalFnc: func(ctx *Context) string { 275 return m.Value 276 }, 277 } 278 } 279 280 // Append a value to the string 281 func (m *MutableStringVariable) Append(_ *Context, value interface{}) error { 282 switch value := value.(type) { 283 case string: 284 m.Value += value 285 default: 286 return errAppendNotSupported 287 } 288 return nil 289 } 290 291 // Set the variable with the specified value 292 func (m *MutableStringVariable) Set(_ *Context, value interface{}) error { 293 m.Value = value.(string) 294 return nil 295 } 296 297 // NewMutableStringVariable returns a new mutable string variable 298 func NewMutableStringVariable() *MutableStringVariable { 299 return &MutableStringVariable{} 300 } 301 302 // MutableStringArrayVariable describes a mutable string array variable 303 type MutableStringArrayVariable struct { 304 StringValues 305 } 306 307 // Set the variable with the specified value 308 func (m *MutableStringArrayVariable) Set(_ *Context, values interface{}) error { 309 if s, ok := values.(string); ok { 310 values = []string{s} 311 } 312 313 m.StringValues = StringValues{} 314 for _, v := range values.([]string) { 315 m.AppendScalarValue(v) 316 } 317 return nil 318 } 319 320 // Append a value to the array 321 func (m *MutableStringArrayVariable) Append(_ *Context, value interface{}) error { 322 switch value := value.(type) { 323 case string: 324 m.AppendScalarValue(value) 325 case []string: 326 for _, v := range value { 327 m.AppendScalarValue(v) 328 } 329 default: 330 return errAppendNotSupported 331 } 332 return nil 333 } 334 335 // GetEvaluator returns the variable SECL evaluator 336 func (m *MutableStringArrayVariable) GetEvaluator() interface{} { 337 return &StringArrayEvaluator{ 338 EvalFnc: func(ctx *Context) []string { 339 return m.GetScalarValues() 340 }, 341 } 342 } 343 344 // NewMutableStringArrayVariable returns a new mutable string array variable 345 func NewMutableStringArrayVariable() *MutableStringArrayVariable { 346 return &MutableStringArrayVariable{} 347 } 348 349 // MutableIntArrayVariable describes a mutable integer array variable 350 type MutableIntArrayVariable struct { 351 Values []int 352 } 353 354 // Set the variable with the specified value 355 func (m *MutableIntArrayVariable) Set(_ *Context, values interface{}) error { 356 if i, ok := values.(int); ok { 357 values = []int{i} 358 } 359 m.Values = values.([]int) 360 return nil 361 } 362 363 // Append a value to the array 364 func (m *MutableIntArrayVariable) Append(_ *Context, value interface{}) error { 365 switch value := value.(type) { 366 case int: 367 m.Values = append(m.Values, value) 368 case []int: 369 m.Values = append(m.Values, value...) 370 default: 371 return errAppendNotSupported 372 } 373 return nil 374 } 375 376 // GetEvaluator returns the variable SECL evaluator 377 func (m *MutableIntArrayVariable) GetEvaluator() interface{} { 378 return &IntArrayEvaluator{ 379 EvalFnc: func(ctx *Context) []int { 380 return m.Values 381 }, 382 } 383 } 384 385 // NewMutableIntArrayVariable returns a new mutable integer array variable 386 func NewMutableIntArrayVariable() *MutableIntArrayVariable { 387 return &MutableIntArrayVariable{} 388 } 389 390 // ScopedVariable is the interface to be implemented by scoped variable in order to be released 391 type ScopedVariable interface { 392 SetReleaseCallback(callback func()) 393 } 394 395 // Scoper maps a variable to the entity its scoped to 396 type Scoper func(ctx *Context) ScopedVariable 397 398 // GlobalVariables holds a set of global variables 399 type GlobalVariables struct{} 400 401 // GetVariable returns new variable of the type of the specified value 402 func (v *GlobalVariables) GetVariable(_ string, value interface{}) (VariableValue, error) { 403 switch value := value.(type) { 404 case bool: 405 return NewMutableBoolVariable(), nil 406 case int: 407 return NewMutableIntVariable(), nil 408 case string: 409 return NewMutableStringVariable(), nil 410 case []string: 411 return NewMutableStringArrayVariable(), nil 412 case []int: 413 return NewMutableIntArrayVariable(), nil 414 default: 415 return nil, fmt.Errorf("unsupported value type: %s", reflect.TypeOf(value)) 416 } 417 } 418 419 // Variables holds a set of variables 420 type Variables struct { 421 vars map[string]interface{} 422 } 423 424 // GetBool returns the boolean value of the specified variable 425 func (v *Variables) GetBool(name string) bool { 426 if _, found := v.vars[name]; !found { 427 return false 428 } 429 return v.vars[name].(bool) 430 } 431 432 // GetInt returns the integer value of the specified variable 433 func (v *Variables) GetInt(name string) int { 434 if _, found := v.vars[name]; !found { 435 return 0 436 } 437 return v.vars[name].(int) 438 } 439 440 // GetString returns the string value of the specified variable 441 func (v *Variables) GetString(name string) string { 442 if _, found := v.vars[name]; !found { 443 return "" 444 } 445 return v.vars[name].(string) 446 } 447 448 // GetStringArray returns the string array value of the specified variable 449 func (v *Variables) GetStringArray(name string) []string { 450 if _, found := v.vars[name]; !found { 451 return nil 452 } 453 return v.vars[name].([]string) 454 } 455 456 // GetIntArray returns the integer array value of the specified variable 457 func (v *Variables) GetIntArray(name string) []int { 458 if _, found := v.vars[name]; !found { 459 return nil 460 } 461 return v.vars[name].([]int) 462 } 463 464 // Set the value of the specified variable 465 func (v *Variables) Set(name string, value interface{}) bool { 466 existed := false 467 if v.vars == nil { 468 v.vars = make(map[string]interface{}) 469 } else { 470 _, existed = v.vars[name] 471 } 472 473 v.vars[name] = value 474 return !existed 475 } 476 477 // ScopedVariables holds a set of scoped variables 478 type ScopedVariables struct { 479 scoper Scoper 480 vars map[ScopedVariable]*Variables 481 } 482 483 // Len returns the length of the variable map 484 func (v *ScopedVariables) Len() int { 485 return len(v.vars) 486 } 487 488 // GetVariable returns new variable of the type of the specified value 489 func (v *ScopedVariables) GetVariable(name string, value interface{}) (VariableValue, error) { 490 getVariables := func(ctx *Context) *Variables { 491 v := v.vars[v.scoper(ctx)] 492 return v 493 } 494 495 setVariable := func(ctx *Context, value interface{}) error { 496 key := v.scoper(ctx) 497 if key == nil { 498 return fmt.Errorf("failed to scope variable '%s'", name) 499 } 500 vars := v.vars[key] 501 if vars == nil { 502 key.SetReleaseCallback(func() { 503 v.ReleaseVariable(key) 504 }) 505 vars = &Variables{} 506 v.vars[key] = vars 507 } 508 vars.Set(name, value) 509 return nil 510 } 511 512 switch value.(type) { 513 case int: 514 return NewIntVariable(func(ctx *Context) int { 515 if vars := getVariables(ctx); vars != nil { 516 return vars.GetInt(name) 517 } 518 return 0 519 }, setVariable), nil 520 case bool: 521 return NewBoolVariable(func(ctx *Context) bool { 522 if vars := getVariables(ctx); vars != nil { 523 return vars.GetBool(name) 524 } 525 return false 526 }, setVariable), nil 527 case string: 528 return NewStringVariable(func(ctx *Context) string { 529 if vars := getVariables(ctx); vars != nil { 530 return vars.GetString(name) 531 } 532 return "" 533 }, setVariable), nil 534 case []string: 535 return NewStringArrayVariable(func(ctx *Context) []string { 536 if vars := getVariables(ctx); vars != nil { 537 return vars.GetStringArray(name) 538 } 539 return nil 540 }, setVariable), nil 541 case []int: 542 return NewIntArrayVariable(func(ctx *Context) []int { 543 if vars := getVariables(ctx); vars != nil { 544 return vars.GetIntArray(name) 545 } 546 return nil 547 548 }, setVariable), nil 549 default: 550 return nil, fmt.Errorf("unsupported variable type %s for '%s'", reflect.TypeOf(value), name) 551 } 552 } 553 554 // ReleaseVariable releases a scoped variable 555 func (v *ScopedVariables) ReleaseVariable(key ScopedVariable) { 556 delete(v.vars, key) 557 } 558 559 // NewScopedVariables returns a new set of scope variables 560 func NewScopedVariables(scoper Scoper) *ScopedVariables { 561 return &ScopedVariables{ 562 scoper: scoper, 563 vars: make(map[ScopedVariable]*Variables), 564 } 565 }