Skip to content

Commit

Permalink
[CSM] Support constants in secl arrays (#26780)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gui774ume authored Jun 18, 2024
1 parent 628d205 commit 0dc8216
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 2 deletions.
1 change: 1 addition & 0 deletions pkg/security/secl/compiler/ast/secl.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,4 +248,5 @@ type Array struct {
StringMembers []StringMember `parser:"| \"[\" @@ { \",\" @@ } \"]\""`
CIDRMembers []CIDRMember `parser:"| \"[\" @@ { \",\" @@ } \"]\""`
Numbers []int `parser:"| \"[\" @Int { \",\" @Int } \"]\""`
Idents []string `parser:"| \"[\" @Ident { \",\" @Ident } \"]\""`
}
36 changes: 36 additions & 0 deletions pkg/security/secl/compiler/eval/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,42 @@ func arrayToEvaluator(array *ast.Array, opts *Opts, state *State) (interface{},

// could be an iterator
return identToEvaluator(&ident{Pos: array.Pos, Ident: array.Ident}, opts, state)
} else if len(array.Idents) != 0 {
// Only "Constants" idents are supported, and only string, int and boolean constants are expected.
// Determine the type with the first ident
switch reflect.TypeOf(opts.Constants[array.Idents[0]]) {
case reflect.TypeOf(&IntEvaluator{}):
var evaluator IntArrayEvaluator
for _, item := range array.Idents {
itemEval, ok := opts.Constants[item].(*IntEvaluator)
if !ok {
return nil, array.Pos, fmt.Errorf("can't mix constants types in arrays: `%s` is not of type int", item)
}
evaluator.AppendValues(itemEval.Value)
}
return &evaluator, array.Pos, nil
case reflect.TypeOf(&StringEvaluator{}):
var evaluator StringValuesEvaluator
for _, item := range array.Idents {
itemEval, ok := opts.Constants[item].(*StringEvaluator)
if !ok {
return nil, array.Pos, fmt.Errorf("can't mix constants types in arrays: `%s` is not of type string", item)
}
evaluator.AppendMembers(ast.StringMember{String: &itemEval.Value})
}
return &evaluator, array.Pos, nil
case reflect.TypeOf(&BoolEvaluator{}):
var evaluator BoolArrayEvaluator
for _, item := range array.Idents {
itemEval, ok := opts.Constants[item].(*BoolEvaluator)
if !ok {
return nil, array.Pos, fmt.Errorf("can't mix constants types in arrays: `%s` is not of type bool", item)
}
evaluator.AppendValues(itemEval.Value)
}
return &evaluator, array.Pos, nil
}
return nil, array.Pos, fmt.Errorf("array of unsupported identifiers (ident type: `%s`)", reflect.TypeOf(opts.Constants[array.Idents[0]]))
} else if array.Variable != nil {
varName, ok := isVariableName(*array.Variable)
if !ok {
Expand Down
38 changes: 38 additions & 0 deletions pkg/security/secl/compiler/eval/eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ func TestVariables(t *testing.T) {

func TestInArray(t *testing.T) {
event := &testEvent{
retval: int(syscall.EACCES),
process: testProcess{
name: "aaa",
uid: 3,
Expand Down Expand Up @@ -425,6 +426,8 @@ func TestInArray(t *testing.T) {
{Expr: `process.name not in [ r".*d.*", r"ab.*" ]`, Expected: true},
{Expr: `process.name in [ "bbb", "aaa" ]`, Expected: true},
{Expr: `process.name not in [ "bbb", "aaa" ]`, Expected: false},
{Expr: `retval in [ EPERM, EACCES, EPFNOSUPPORT ]`, Expected: true},
{Expr: `retval in [ EPERM, EPIPE, EPFNOSUPPORT ]`, Expected: false},
}

for _, test := range tests {
Expand Down Expand Up @@ -568,6 +571,41 @@ func TestPartial(t *testing.T) {
}
}

func TestConstants(t *testing.T) {
tests := []struct {
Expr string
OK bool
Message string
}{
{Expr: `retval in [ EPERM, EACCES ]`, OK: true},
{Expr: `open.filename in [ my_constant_1, my_constant_2 ]`, OK: true},
{Expr: `process.is_root in [ true, false ]`, OK: true},
{Expr: `open.filename in [ EPERM, EACCES ]`, OK: false, Message: "Int array shouldn't be allowed for string field"},
{Expr: `retval in [ EPERM, true ]`, OK: false, Message: "Constants of different types can't be mixed in an array"},
}

for _, test := range tests {
model := &testModel{}

opts := newOptsWithParams(testConstants, nil)

_, err := parseRule(test.Expr, model, opts)
if !test.OK {
if err == nil {
var msg string
if len(test.Message) > 0 {
msg = fmt.Sprintf(": reason: %s", test.Message)
}
t.Fatalf("expected an error for `%s`%s", test.Expr, msg)
}
} else {
if err != nil {
t.Fatalf("error while parsing `%s`: %v", test.Expr, err)
}
}
}
}

func TestMacroList(t *testing.T) {
model := &testModel{}
pc := ast.NewParsingContext()
Expand Down
5 changes: 5 additions & 0 deletions pkg/security/secl/compiler/eval/evaluators.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,11 @@ func (b *BoolArrayEvaluator) IsStatic() bool {
return b.EvalFnc == nil
}

// AppendValues to the array evaluator
func (b *BoolArrayEvaluator) AppendValues(values ...bool) {
b.Values = append(b.Values, values...)
}

// CIDREvaluator returns a net.IP
type CIDREvaluator struct {
EvalFnc func(ctx *Context) net.IPNet
Expand Down
39 changes: 37 additions & 2 deletions pkg/security/secl/compiler/eval/model_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,9 @@ type testNetwork struct {
}

type testEvent struct {
id string
kind string
id string
kind string
retval int

process testProcess
network testNetwork
Expand Down Expand Up @@ -478,6 +479,13 @@ func (m *testModel) GetEvaluator(field Field, _ RegisterID) (Evaluator, error) {
Field: field,
}, nil

case "retval":

return &IntEvaluator{
EvalFnc: func(ctx *Context) int { return ctx.Event.(*testEvent).retval },
Field: field,
}, nil

case "mkdir.filename":

return &StringEvaluator{
Expand Down Expand Up @@ -545,6 +553,10 @@ func (e *testEvent) GetFieldValue(field Field) (interface{}, error) {

return e.open.filename, nil

case "retval":

return e.retval, nil

case "open.flags":

return e.open.flags, nil
Expand Down Expand Up @@ -653,6 +665,10 @@ func (e *testEvent) GetFieldEventType(field Field) (string, error) {

return "open", nil

case "retval":

return "*", nil

case "open.flags":

return "open", nil
Expand Down Expand Up @@ -740,6 +756,11 @@ func (e *testEvent) SetFieldValue(field Field, value interface{}) error {
e.open.filename = value.(string)
return nil

case "retval":

e.retval = value.(int)
return nil

case "open.flags":

e.open.flags = value.(int)
Expand Down Expand Up @@ -835,6 +856,10 @@ func (e *testEvent) GetFieldType(field Field) (reflect.Kind, error) {

return reflect.String, nil

case "retval":

return reflect.Int, nil

case "open.flags":

return reflect.Int, nil
Expand Down Expand Up @@ -870,4 +895,14 @@ var testConstants = map[string]interface{}{
"O_EXCL": &IntEvaluator{Value: syscall.O_EXCL},
"O_SYNC": &IntEvaluator{Value: syscall.O_SYNC},
"O_TRUNC": &IntEvaluator{Value: syscall.O_TRUNC},

// retval
"EPERM": &IntEvaluator{Value: int(syscall.EPERM)},
"EACCES": &IntEvaluator{Value: int(syscall.EACCES)},
"EPFNOSUPPORT": &IntEvaluator{Value: int(syscall.EPFNOSUPPORT)},
"EPIPE": &IntEvaluator{Value: int(syscall.EPIPE)},

// string constants
"my_constant_1": &StringEvaluator{Value: "my_constant_1"},
"my_constant_2": &StringEvaluator{Value: "my_constant_2"},
}

0 comments on commit 0dc8216

Please sign in to comment.