github.com/DataDog/datadog-agent/pkg/security/secl@v0.55.0-devel.0.20240517055856-10c4965fea94/rules/actions.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  	"fmt"
    12  
    13  	"github.com/DataDog/datadog-agent/pkg/security/secl/compiler/ast"
    14  	"github.com/DataDog/datadog-agent/pkg/security/secl/compiler/eval"
    15  	"github.com/DataDog/datadog-agent/pkg/security/secl/model"
    16  )
    17  
    18  // ActionName defines an action name
    19  type ActionName = string
    20  
    21  const (
    22  	// KillAction name a the kill action
    23  	KillAction ActionName = "kill"
    24  )
    25  
    26  // ActionDefinition describes a rule action section
    27  type ActionDefinition struct {
    28  	Filter *string         `yaml:"filter"`
    29  	Set    *SetDefinition  `yaml:"set"`
    30  	Kill   *KillDefinition `yaml:"kill"`
    31  
    32  	// internal
    33  	InternalCallback *InternalCallbackDefinition
    34  	FilterEvaluator  *eval.RuleEvaluator
    35  }
    36  
    37  // Check returns an error if the action in invalid
    38  func (a *ActionDefinition) Check(opts PolicyLoaderOpts) error {
    39  	if a.Set == nil && a.InternalCallback == nil && a.Kill == nil {
    40  		return errors.New("either 'set' or 'kill' section of an action must be specified")
    41  	}
    42  
    43  	if a.Set != nil {
    44  		if a.Kill != nil {
    45  			return errors.New("only of 'set' or 'kill' section of an action can be specified")
    46  		}
    47  
    48  		if a.Set.Name == "" {
    49  			return errors.New("action name is empty")
    50  		}
    51  
    52  		if (a.Set.Value == nil && a.Set.Field == "") || (a.Set.Value != nil && a.Set.Field != "") {
    53  			return errors.New("either 'value' or 'field' must be specified")
    54  		}
    55  	} else if a.Kill != nil {
    56  		if opts.DisableEnforcement {
    57  			a.Kill = nil
    58  			return errors.New("'kill' action is disabled globally")
    59  		}
    60  
    61  		if a.Kill.Signal == "" {
    62  			return errors.New("a valid signal has to be specified to the 'kill' action")
    63  		}
    64  
    65  		if _, found := model.SignalConstants[a.Kill.Signal]; !found {
    66  			return fmt.Errorf("unsupported signal '%s'", a.Kill.Signal)
    67  		}
    68  	}
    69  
    70  	return nil
    71  }
    72  
    73  // CompileFilter compiles the filter expression
    74  func (a *ActionDefinition) CompileFilter(parsingContext *ast.ParsingContext, model eval.Model, evalOpts *eval.Opts) error {
    75  	if a.Filter == nil || *a.Filter == "" {
    76  		return nil
    77  	}
    78  
    79  	expression := *a.Filter
    80  
    81  	rule := &Rule{
    82  		Rule: eval.NewRule("action_rule", expression, evalOpts),
    83  	}
    84  
    85  	if err := rule.Parse(parsingContext); err != nil {
    86  		return &ErrActionFilter{Expression: expression, Err: err}
    87  	}
    88  
    89  	if err := rule.GenEvaluator(model, parsingContext); err != nil {
    90  		return &ErrActionFilter{Expression: expression, Err: err}
    91  	}
    92  
    93  	a.FilterEvaluator = rule.GetEvaluator()
    94  
    95  	return nil
    96  }
    97  
    98  // IsAccepted returns whether a filter is accepted and has to be executed
    99  func (a *ActionDefinition) IsAccepted(ctx *eval.Context) bool {
   100  	return a.FilterEvaluator == nil || a.FilterEvaluator.Eval(ctx)
   101  }
   102  
   103  // Scope describes the scope variables
   104  type Scope string
   105  
   106  // SetDefinition describes the 'set' section of a rule action
   107  type SetDefinition struct {
   108  	Name   string      `yaml:"name"`
   109  	Value  interface{} `yaml:"value"`
   110  	Field  string      `yaml:"field"`
   111  	Append bool        `yaml:"append"`
   112  	Scope  Scope       `yaml:"scope"`
   113  }
   114  
   115  // InternalCallbackDefinition describes an internal rule action
   116  type InternalCallbackDefinition struct{}
   117  
   118  // KillDefinition describes the 'kill' section of a rule action
   119  type KillDefinition struct {
   120  	Signal string `yaml:"signal"`
   121  	Scope  string `yaml:"scope"`
   122  }