github.com/DataDog/datadog-agent/pkg/security/secl@v0.55.0-devel.0.20240517055856-10c4965fea94/compiler/eval/eval_test.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  	"container/list"
    11  	"fmt"
    12  	"net"
    13  	"os"
    14  	"runtime"
    15  	"strings"
    16  	"syscall"
    17  	"testing"
    18  	"time"
    19  
    20  	"github.com/DataDog/datadog-agent/pkg/security/secl/compiler/ast"
    21  )
    22  
    23  func newOptsWithParams(constants map[string]interface{}, legacyFields map[Field]Field) *Opts {
    24  	opts := &Opts{
    25  		Constants:    constants,
    26  		LegacyFields: legacyFields,
    27  	}
    28  
    29  	variables := map[string]VariableValue{
    30  		"pid": NewIntVariable(func(ctx *Context) int {
    31  			return os.Getpid()
    32  		}, nil),
    33  		"str": NewStringVariable(func(ctx *Context) string {
    34  			return "aaa"
    35  		}, nil),
    36  	}
    37  
    38  	return opts.WithVariables(variables).WithMacroStore(&MacroStore{})
    39  }
    40  
    41  func parseRule(expr string, model Model, opts *Opts) (*Rule, error) {
    42  	rule := NewRule("id1", expr, opts)
    43  
    44  	pc := ast.NewParsingContext()
    45  
    46  	if err := rule.Parse(pc); err != nil {
    47  		return nil, fmt.Errorf("parsing error: %v", err)
    48  	}
    49  
    50  	if err := rule.GenEvaluator(model, pc); err != nil {
    51  		return rule, fmt.Errorf("compilation error: %v", err)
    52  	}
    53  
    54  	return rule, nil
    55  }
    56  
    57  func eval(_ *testing.T, event *testEvent, expr string) (bool, *ast.Rule, error) {
    58  	model := &testModel{}
    59  
    60  	ctx := NewContext(event)
    61  
    62  	opts := newOptsWithParams(testConstants, nil)
    63  
    64  	rule, err := parseRule(expr, model, opts)
    65  	if err != nil {
    66  		return false, nil, err
    67  	}
    68  	r1 := rule.Eval(ctx)
    69  
    70  	return r1, rule.GetAst(), nil
    71  }
    72  
    73  func TestStringError(t *testing.T) {
    74  	model := &testModel{}
    75  
    76  	opts := newOptsWithParams(nil, nil)
    77  	rule, err := parseRule(`process.name != "/usr/bin/vipw" && process.uid != 0 && open.filename == 3`, model, opts)
    78  	if rule == nil {
    79  		t.Fatal(err)
    80  	}
    81  
    82  	_, err = NewRuleEvaluator(rule.GetAst(), model, opts)
    83  	if err == nil || err.(*ErrAstToEval).Pos.Column != 73 {
    84  		t.Fatal("should report a string type error")
    85  	}
    86  }
    87  
    88  func TestIntError(t *testing.T) {
    89  	model := &testModel{}
    90  
    91  	opts := newOptsWithParams(nil, nil)
    92  	rule, err := parseRule(`process.name != "/usr/bin/vipw" && process.uid != "test" && Open.Filename == "/etc/shadow"`, model, opts)
    93  	if rule == nil {
    94  		t.Fatal(err)
    95  	}
    96  
    97  	_, err = NewRuleEvaluator(rule.GetAst(), model, opts)
    98  	if err == nil || err.(*ErrAstToEval).Pos.Column != 51 {
    99  		t.Fatal("should report a string type error")
   100  	}
   101  }
   102  
   103  func TestBoolError(t *testing.T) {
   104  	model := &testModel{}
   105  
   106  	opts := newOptsWithParams(nil, nil)
   107  	rule, err := parseRule(`(process.name != "/usr/bin/vipw") == "test"`, model, opts)
   108  	if rule == nil {
   109  		t.Fatal(err)
   110  	}
   111  
   112  	_, err = NewRuleEvaluator(rule.GetAst(), model, opts)
   113  	if err == nil || err.(*ErrAstToEval).Pos.Column != 38 {
   114  		t.Fatal("should report a bool type error")
   115  	}
   116  }
   117  
   118  func TestSimpleString(t *testing.T) {
   119  	event := &testEvent{
   120  		process: testProcess{
   121  			name: "/usr/bin/cat",
   122  			uid:  1,
   123  		},
   124  	}
   125  
   126  	tests := []struct {
   127  		Expr     string
   128  		Expected bool
   129  	}{
   130  		{Expr: `process.name != ""`, Expected: true},
   131  		{Expr: `process.name != "/usr/bin/vipw"`, Expected: true},
   132  		{Expr: `process.name != "/usr/bin/cat"`, Expected: false},
   133  		{Expr: `process.name == "/usr/bin/cat"`, Expected: true},
   134  		{Expr: `process.name == "/usr/bin/vipw"`, Expected: false},
   135  		{Expr: `(process.name == "/usr/bin/cat" && process.uid == 0) && (process.name == "/usr/bin/cat" && process.uid == 0)`, Expected: false},
   136  		{Expr: `(process.name == "/usr/bin/cat" && process.uid == 1) && (process.name == "/usr/bin/cat" && process.uid == 1)`, Expected: true},
   137  	}
   138  
   139  	for _, test := range tests {
   140  		result, _, err := eval(t, event, test.Expr)
   141  		if err != nil {
   142  			t.Fatalf("error while evaluating `%s`: %s", test.Expr, err)
   143  		}
   144  
   145  		if result != test.Expected {
   146  			t.Errorf("expected result `%t` not found, got `%t`\n%s", test.Expected, result, test.Expr)
   147  		}
   148  	}
   149  }
   150  
   151  func TestSimpleInt(t *testing.T) {
   152  	event := &testEvent{
   153  		process: testProcess{
   154  			uid: 444,
   155  		},
   156  	}
   157  
   158  	tests := []struct {
   159  		Expr     string
   160  		Expected bool
   161  	}{
   162  		{Expr: `111 != 555`, Expected: true},
   163  		{Expr: `process.uid != 555`, Expected: true},
   164  		{Expr: `process.uid != 444`, Expected: false},
   165  		{Expr: `process.uid == 444`, Expected: true},
   166  		{Expr: `process.uid == 555`, Expected: false},
   167  		{Expr: `--3 == 3`, Expected: true},
   168  		{Expr: `3 ^ 3 == 0`, Expected: true},
   169  		{Expr: `^0 == -1`, Expected: true},
   170  	}
   171  
   172  	for _, test := range tests {
   173  		result, _, err := eval(t, event, test.Expr)
   174  		if err != nil {
   175  			t.Fatalf("error while evaluating `%s`: %s", test.Expr, err)
   176  		}
   177  
   178  		if result != test.Expected {
   179  			t.Errorf("expected result `%t` not found, got `%t`\n%s", test.Expected, result, test.Expr)
   180  		}
   181  	}
   182  }
   183  
   184  func TestSimpleBool(t *testing.T) {
   185  	event := &testEvent{}
   186  
   187  	tests := []struct {
   188  		Expr     string
   189  		Expected bool
   190  	}{
   191  		{Expr: `(444 == 444) && ("test" == "test")`, Expected: true},
   192  		{Expr: `(444 == 444) and ("test" == "test")`, Expected: true},
   193  		{Expr: `(444 != 444) && ("test" == "test")`, Expected: false},
   194  		{Expr: `(444 != 555) && ("test" == "test")`, Expected: true},
   195  		{Expr: `(444 != 555) && ("test" != "aaaa")`, Expected: true},
   196  		{Expr: `(444 != 555) && # blah blah
   197  		# blah blah
   198  		("test" != "aaaa")`, Expected: true},
   199  		{Expr: `(444 != 555) && # blah blah
   200  		# blah blah
   201  		("test" == "aaaa")`, Expected: false},
   202  	}
   203  
   204  	for _, test := range tests {
   205  		result, _, err := eval(t, event, test.Expr)
   206  		if err != nil {
   207  			t.Fatalf("error while evaluating `%s`: %s", test.Expr, err)
   208  		}
   209  
   210  		if result != test.Expected {
   211  			t.Errorf("expected result `%t` not found, got `%t`\n%s", test.Expected, result, test.Expr)
   212  		}
   213  	}
   214  }
   215  
   216  func TestPrecedence(t *testing.T) {
   217  	event := &testEvent{}
   218  
   219  	tests := []struct {
   220  		Expr     string
   221  		Expected bool
   222  	}{
   223  		{Expr: `false || (true != true)`, Expected: false},
   224  		{Expr: `false || true`, Expected: true},
   225  		{Expr: `false or true`, Expected: true},
   226  		{Expr: `1 == 1 & 1`, Expected: true},
   227  		{Expr: `not true && false`, Expected: false},
   228  		{Expr: `not (true && false)`, Expected: true},
   229  	}
   230  
   231  	for _, test := range tests {
   232  		result, _, err := eval(t, event, test.Expr)
   233  		if err != nil {
   234  			t.Fatalf("error while evaluating `%s`: %s", test.Expr, err)
   235  		}
   236  
   237  		if result != test.Expected {
   238  			t.Errorf("expected result `%t` not found, got `%t`\n%s", test.Expected, result, test.Expr)
   239  		}
   240  	}
   241  }
   242  
   243  func TestParenthesis(t *testing.T) {
   244  	event := &testEvent{}
   245  
   246  	tests := []struct {
   247  		Expr     string
   248  		Expected bool
   249  	}{
   250  		{Expr: `(true) == (true)`, Expected: true},
   251  	}
   252  
   253  	for _, test := range tests {
   254  		result, _, err := eval(t, event, test.Expr)
   255  		if err != nil {
   256  			t.Fatalf("error while evaluating `%s`: %s", test.Expr, err)
   257  		}
   258  
   259  		if result != test.Expected {
   260  			t.Errorf("expected result `%t` not found, got `%t`\n%s", test.Expected, result, test.Expr)
   261  		}
   262  	}
   263  }
   264  
   265  func TestSimpleBitOperations(t *testing.T) {
   266  	event := &testEvent{}
   267  
   268  	tests := []struct {
   269  		Expr     string
   270  		Expected bool
   271  	}{
   272  		{Expr: `(3 & 3) == 3`, Expected: true},
   273  		{Expr: `(3 & 1) == 3`, Expected: false},
   274  		{Expr: `(2 | 1) == 3`, Expected: true},
   275  		{Expr: `(3 & 1) != 0`, Expected: true},
   276  		{Expr: `0 != 3 & 1`, Expected: true},
   277  		{Expr: `(3 ^ 3) == 0`, Expected: true},
   278  	}
   279  
   280  	for _, test := range tests {
   281  		result, _, err := eval(t, event, test.Expr)
   282  		if err != nil {
   283  			t.Fatalf("error while evaluating `%s`", test.Expr)
   284  		}
   285  
   286  		if result != test.Expected {
   287  			t.Errorf("expected result `%t` not found, got `%t`\n%s", test.Expected, result, test.Expr)
   288  		}
   289  	}
   290  }
   291  
   292  func TestStringMatcher(t *testing.T) {
   293  	event := &testEvent{
   294  		process: testProcess{
   295  			name:  "/usr/bin/c$t",
   296  			argv0: "http://example.com",
   297  		},
   298  		open: testOpen{
   299  			filename: "dGVzdA==.dGVzdA==.dGVzdA==.dGVzdA==.dGVzdA==.example.com",
   300  		},
   301  	}
   302  
   303  	tests := []struct {
   304  		Expr     string
   305  		Expected bool
   306  	}{
   307  		{Expr: `process.name =~ "/usr/bin/c$t/test/*"`, Expected: false},
   308  		{Expr: `process.name =~ "/usr/bin/c$t/test/**"`, Expected: false},
   309  		{Expr: `process.name =~ "/usr/bin/c$t/*"`, Expected: false},
   310  		{Expr: `process.name =~ "/usr/bin/c$t/**"`, Expected: false},
   311  		{Expr: `process.name =~ "/usr/bin/c$t*"`, Expected: true},
   312  		{Expr: `process.name =~ "/usr/bin/c*"`, Expected: true},
   313  		{Expr: `process.name =~ "/usr/bin/l*"`, Expected: false},
   314  		{Expr: `process.name =~ "/usr/bin/**"`, Expected: true},
   315  		{Expr: `process.name =~ "/usr/**"`, Expected: true},
   316  		{Expr: `process.name =~ "/**"`, Expected: true},
   317  		{Expr: `process.name =~ "/etc/**"`, Expected: false},
   318  		{Expr: `process.name =~ ""`, Expected: false},
   319  		{Expr: `process.name =~ "*"`, Expected: false},
   320  		{Expr: `process.name =~ "/*"`, Expected: false},
   321  		{Expr: `process.name =~ "*/*"`, Expected: false},
   322  		{Expr: `process.name =~ "/*/*/*"`, Expected: true},
   323  		{Expr: `process.name =~ "/usr/bin/*"`, Expected: true},
   324  		{Expr: `process.name =~ "/usr/sbin/*"`, Expected: false},
   325  		{Expr: `process.name !~ "/usr/sbin/*"`, Expected: true},
   326  		{Expr: `process.name =~ "/bin/"`, Expected: false},
   327  		{Expr: `process.name =~ "/bin/*"`, Expected: false},
   328  		{Expr: `process.name =~ "*/bin/*"`, Expected: true},
   329  		{Expr: `process.name =~ "*/bin"`, Expected: false},
   330  		{Expr: `process.name =~ "/usr/*/c$t"`, Expected: true},
   331  		{Expr: `process.name =~ "/usr/*/bin/*"`, Expected: false},
   332  		{Expr: `process.name == ~"/usr/bin/*"`, Expected: true},
   333  		{Expr: `process.name == ~"/usr/sbin/*"`, Expected: false},
   334  		{Expr: `process.name =~ ~"/usr/bin/*"`, Expected: true},
   335  		{Expr: `process.name =~ "/usr/bin/c$t"`, Expected: true},
   336  		{Expr: `process.name =~ "/usr/bin/c$taaa"`, Expected: false},
   337  		{Expr: `process.name =~ r".*/bin/.*"`, Expected: true},
   338  		{Expr: `process.name =~ r".*/[usr]+/bin/.*"`, Expected: true},
   339  		{Expr: `process.name =~ r".*/[abc]+/bin/.*"`, Expected: false},
   340  		{Expr: `process.name == r".*/bin/.*"`, Expected: true},
   341  		{Expr: `r".*/bin/.*" == process.name`, Expected: true},
   342  		{Expr: `process.argv0 =~ "http://*"`, Expected: true},
   343  		{Expr: `process.argv0 =~ "*example.com"`, Expected: true},
   344  		{Expr: `open.filename == r"^((?:[A-Za-z\d+]{4})*(?:[A-Za-z\d+]{3}=|[A-Za-z\d+]{2}==)\.)*(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$"`, Expected: true},
   345  	}
   346  
   347  	for _, test := range tests {
   348  		result, _, err := eval(t, event, test.Expr)
   349  		if err != nil {
   350  			t.Fatalf("error while evaluating `%s`: %s", test.Expr, err)
   351  		}
   352  
   353  		if result != test.Expected {
   354  			t.Errorf("expected result `%t` not found, got `%t`\n%s", test.Expected, result, test.Expr)
   355  		}
   356  	}
   357  }
   358  
   359  func TestVariables(t *testing.T) {
   360  	event := &testEvent{
   361  		process: testProcess{
   362  			name: fmt.Sprintf("/proc/%d/maps/aaa", os.Getpid()),
   363  			pid:  os.Getpid(),
   364  		},
   365  	}
   366  
   367  	tests := []struct {
   368  		Expr     string
   369  		Expected bool
   370  	}{
   371  		{Expr: `process.name == "/proc/${pid}/maps/${str}"`, Expected: true},
   372  		{Expr: `process.name == "/proc/${pid}/maps/${str}3"`, Expected: false},
   373  		{Expr: `process.name == "/proc/${pid}/maps/${str"`, Expected: false},
   374  		{Expr: `process.name == "/proc/${pid/maps/${str"`, Expected: false},
   375  		{Expr: `process.pid == ${pid}`, Expected: true},
   376  	}
   377  
   378  	for _, test := range tests {
   379  		result, _, err := eval(t, event, test.Expr)
   380  		if err != nil {
   381  			t.Fatalf("error while evaluating `%s`: %s", test.Expr, err)
   382  		}
   383  
   384  		if result != test.Expected {
   385  			t.Errorf("expected result `%t` not found, got `%t`\n%s", test.Expected, result, test.Expr)
   386  		}
   387  	}
   388  }
   389  
   390  func TestInArray(t *testing.T) {
   391  	event := &testEvent{
   392  		process: testProcess{
   393  			name: "aaa",
   394  			uid:  3,
   395  		},
   396  	}
   397  
   398  	tests := []struct {
   399  		Expr     string
   400  		Expected bool
   401  	}{
   402  		{Expr: `"a" in [ "a", "b", "c" ]`, Expected: true},
   403  		{Expr: `process.name in [ "c", "b", "aaa" ]`, Expected: true},
   404  		{Expr: `"d" in [ "aaa", "b", "c" ]`, Expected: false},
   405  		{Expr: `process.name in [ "c", "b", "z" ]`, Expected: false},
   406  		{Expr: `"aaa" not in [ "aaa", "b", "c" ]`, Expected: false},
   407  		{Expr: `process.name not in [ "c", "b", "aaa" ]`, Expected: false},
   408  		{Expr: `"d" not in [ "aaa", "b", "c" ]`, Expected: true},
   409  		{Expr: `process.name not in [ "c", "b", "z" ]`, Expected: true},
   410  		{Expr: `3 in [ 1, 2, 3 ]`, Expected: true},
   411  		{Expr: `process.uid in [ 1, 2, 3 ]`, Expected: true},
   412  		{Expr: `4 in [ 1, 2, 3 ]`, Expected: false},
   413  		{Expr: `process.uid in [ 4, 2, 1 ]`, Expected: false},
   414  		{Expr: `3 not in [ 1, 2, 3 ]`, Expected: false},
   415  		{Expr: `3 not in [ 1, 2, 3 ]`, Expected: false},
   416  		{Expr: `4 not in [ 1, 2, 3 ]`, Expected: true},
   417  		{Expr: `4 not in [ 3, 2, 1 ]`, Expected: true},
   418  		{Expr: `process.name in [ ~"*a*" ]`, Expected: true},
   419  		{Expr: `process.name in [ ~"*d*" ]`, Expected: false},
   420  		{Expr: `process.name in [ ~"*d*", "aaa" ]`, Expected: true},
   421  		{Expr: `process.name in [ ~"*d*", "aa*" ]`, Expected: false},
   422  		{Expr: `process.name in [ ~"*d*", ~"aa*" ]`, Expected: true},
   423  		{Expr: `process.name in [ r".*d.*", r"aa.*" ]`, Expected: true},
   424  		{Expr: `process.name in [ r".*d.*", r"ab.*" ]`, Expected: false},
   425  		{Expr: `process.name not in [ r".*d.*", r"ab.*" ]`, Expected: true},
   426  		{Expr: `process.name in [ "bbb", "aaa" ]`, Expected: true},
   427  		{Expr: `process.name not in [ "bbb", "aaa" ]`, Expected: false},
   428  	}
   429  
   430  	for _, test := range tests {
   431  		result, _, err := eval(t, event, test.Expr)
   432  		if err != nil {
   433  			t.Fatalf("error while evaluating `%s: %s`", test.Expr, err)
   434  		}
   435  
   436  		if result != test.Expected {
   437  			t.Errorf("expected result `%t` not found, got `%t`\n%s", test.Expected, result, test.Expr)
   438  		}
   439  	}
   440  }
   441  
   442  func TestComplex(t *testing.T) {
   443  	event := &testEvent{
   444  		open: testOpen{
   445  			filename: "/var/lib/httpd/htpasswd",
   446  			flags:    syscall.O_CREAT | syscall.O_TRUNC | syscall.O_EXCL | syscall.O_RDWR | syscall.O_WRONLY,
   447  		},
   448  	}
   449  
   450  	tests := []struct {
   451  		Expr     string
   452  		Expected bool
   453  	}{
   454  		{Expr: `open.filename =~ "/var/lib/httpd/*" && open.flags & (O_CREAT | O_TRUNC | O_EXCL | O_RDWR | O_WRONLY) > 0`, Expected: true},
   455  	}
   456  
   457  	for _, test := range tests {
   458  		result, _, err := eval(t, event, test.Expr)
   459  		if err != nil {
   460  			t.Fatalf("error while evaluating `%s: %s`", test.Expr, err)
   461  		}
   462  
   463  		if result != test.Expected {
   464  			t.Errorf("expected result `%t` not found, got `%t`\n%s", test.Expected, result, test.Expr)
   465  		}
   466  	}
   467  }
   468  
   469  func TestPartial(t *testing.T) {
   470  	event := &testEvent{
   471  		process: testProcess{
   472  			name:   "abc",
   473  			uid:    123,
   474  			isRoot: true,
   475  		},
   476  		open: testOpen{
   477  			filename: "xyz",
   478  		},
   479  	}
   480  
   481  	variables := make(map[string]VariableValue)
   482  	variables["var"] = NewBoolVariable(
   483  		func(ctx *Context) bool {
   484  			return false
   485  		},
   486  		func(ctx *Context, value interface{}) error {
   487  			return nil
   488  		},
   489  	)
   490  
   491  	tests := []struct {
   492  		Expr        string
   493  		Field       Field
   494  		IsDiscarder bool
   495  	}{
   496  		{Expr: `true || process.name == "/usr/bin/cat"`, Field: "process.name", IsDiscarder: false},
   497  		{Expr: `false || process.name == "/usr/bin/cat"`, Field: "process.name", IsDiscarder: true},
   498  		{Expr: `1 != 1 || process.name == "/usr/bin/cat"`, Field: "process.name", IsDiscarder: true},
   499  		{Expr: `true || process.name == "abc"`, Field: "process.name", IsDiscarder: false},
   500  		{Expr: `false || process.name == "abc"`, Field: "process.name", IsDiscarder: false},
   501  		{Expr: `true && process.name == "/usr/bin/cat"`, Field: "process.name", IsDiscarder: true},
   502  		{Expr: `false && process.name == "/usr/bin/cat"`, Field: "process.name", IsDiscarder: true},
   503  		{Expr: `true && process.name == "abc"`, Field: "process.name", IsDiscarder: false},
   504  		{Expr: `false && process.name == "abc"`, Field: "process.name", IsDiscarder: true},
   505  		{Expr: `open.filename == "test1" && process.name == "/usr/bin/cat"`, Field: "process.name", IsDiscarder: true},
   506  		{Expr: `open.filename == "test1" && process.name != "/usr/bin/cat"`, Field: "process.name", IsDiscarder: false},
   507  		{Expr: `open.filename == "test1" || process.name == "/usr/bin/cat"`, Field: "process.name", IsDiscarder: false},
   508  		{Expr: `open.filename == "test1" || process.name != "/usr/bin/cat"`, Field: "process.name", IsDiscarder: false},
   509  		{Expr: `open.filename == "test1" && !(process.name == "/usr/bin/cat")`, Field: "process.name", IsDiscarder: false},
   510  		{Expr: `open.filename == "test1" && !(process.name != "/usr/bin/cat")`, Field: "process.name", IsDiscarder: true},
   511  		{Expr: `open.filename == "test1" && (process.name =~ "/usr/bin/*" )`, Field: "process.name", IsDiscarder: true},
   512  		{Expr: `open.filename == "test1" && process.name =~ "ab*" `, Field: "process.name", IsDiscarder: false},
   513  		{Expr: `open.filename == "test1" && process.name == open.filename`, Field: "process.name", IsDiscarder: false},
   514  		{Expr: `open.filename =~ "test1" && process.name == "abc"`, Field: "process.name", IsDiscarder: false},
   515  		{Expr: `open.filename in [ "test1", "test2" ] && (process.name == open.filename)`, Field: "process.name", IsDiscarder: false},
   516  		{Expr: `open.filename in [ "test1", "test2" ] && process.name == "abc"`, Field: "process.name", IsDiscarder: false},
   517  		{Expr: `!(open.filename in [ "test1", "test2" ]) && process.name == "abc"`, Field: "process.name", IsDiscarder: false},
   518  		{Expr: `!(open.filename in [ "test1", "xyz" ]) && process.name == "abc"`, Field: "process.name", IsDiscarder: false},
   519  		{Expr: `!(open.filename in [ "test1", "xyz" ]) && process.name == "abc"`, Field: "process.name", IsDiscarder: false},
   520  		{Expr: `!(open.filename in [ "test1", "xyz" ] && true) && process.name == "abc"`, Field: "process.name", IsDiscarder: false},
   521  		{Expr: `!(open.filename in [ "test1", "xyz" ] && false) && process.name == "abc"`, Field: "process.name", IsDiscarder: false},
   522  		{Expr: `!(open.filename in [ "test1", "xyz" ] && false) && !(process.name == "abc")`, Field: "process.name", IsDiscarder: true},
   523  		{Expr: `!(open.filename in [ "test1", "xyz" ] && false) && !(process.name == "abc")`, Field: "open.filename", IsDiscarder: false},
   524  		{Expr: `(open.filename not in [ "test1", "xyz" ] && true) && !(process.name == "abc")`, Field: "open.filename", IsDiscarder: true},
   525  		{Expr: `open.filename == open.filename`, Field: "open.filename", IsDiscarder: false},
   526  		{Expr: `open.filename != open.filename`, Field: "open.filename", IsDiscarder: true},
   527  		{Expr: `open.filename == "test1" && process.uid == 456`, Field: "process.uid", IsDiscarder: true},
   528  		{Expr: `open.filename == "test1" && process.uid == 123`, Field: "process.uid", IsDiscarder: false},
   529  		{Expr: `open.filename == "test1" && !process.is_root`, Field: "process.is_root", IsDiscarder: true},
   530  		{Expr: `open.filename == "test1" && process.is_root`, Field: "process.is_root", IsDiscarder: false},
   531  		{Expr: `open.filename =~ "*test1*"`, Field: "open.filename", IsDiscarder: true},
   532  		{Expr: `process.uid & (1 | 1024) == 1`, Field: "process.uid", IsDiscarder: false},
   533  		{Expr: `process.uid & (1 | 2) == 1`, Field: "process.uid", IsDiscarder: true},
   534  		{Expr: `(open.filename not in [ "test1", "xyz" ] && true) && !(process.name == "abc")`, Field: "open.filename", IsDiscarder: true},
   535  		{Expr: `process.uid == 123 && ${var} == true`, Field: "process.uid", IsDiscarder: false},
   536  		{Expr: `process.uid == 123 && ${var} != true`, Field: "process.uid", IsDiscarder: false},
   537  		{Expr: `process.uid == 678 && ${var} == true`, Field: "process.uid", IsDiscarder: true},
   538  		{Expr: `process.uid == 678 && ${var} != true`, Field: "process.uid", IsDiscarder: true},
   539  		{Expr: `process.name == "abc" && ^process.uid != 0`, Field: "process.name", IsDiscarder: false},
   540  		{Expr: `process.name == "abc" && ^process.uid == 0`, Field: "process.uid", IsDiscarder: true},
   541  		{Expr: `process.name == "abc" && ^process.uid != 0`, Field: "process.uid", IsDiscarder: false},
   542  		{Expr: `process.name == "abc" || ^process.uid == 0`, Field: "process.uid", IsDiscarder: false},
   543  		{Expr: `process.name == "abc" || ^process.uid != 0`, Field: "process.uid", IsDiscarder: false},
   544  		{Expr: `process.name =~ "/usr/sbin/*" && process.uid == 0 && process.is_root`, Field: "process.uid", IsDiscarder: true},
   545  	}
   546  
   547  	ctx := NewContext(event)
   548  
   549  	for _, test := range tests {
   550  		model := &testModel{}
   551  
   552  		opts := newOptsWithParams(testConstants, nil)
   553  		opts.WithVariables(variables)
   554  
   555  		rule, err := parseRule(test.Expr, model, opts)
   556  		if err != nil {
   557  			t.Fatalf("error while evaluating `%s`: %s", test.Expr, err)
   558  		}
   559  
   560  		result, err := rule.PartialEval(ctx, test.Field)
   561  		if err != nil {
   562  			t.Fatalf("error while partial evaluating `%s` for `%s`: %s", test.Expr, test.Field, err)
   563  		}
   564  
   565  		if !result != test.IsDiscarder {
   566  			t.Fatalf("expected result `%t` for `%s`, got `%t`\n%s", test.IsDiscarder, test.Field, !result, test.Expr)
   567  		}
   568  	}
   569  }
   570  
   571  func TestMacroList(t *testing.T) {
   572  	model := &testModel{}
   573  	pc := ast.NewParsingContext()
   574  	opts := newOptsWithParams(make(map[string]interface{}), nil)
   575  
   576  	macro, err := NewMacro(
   577  		"list",
   578  		`[ "/etc/shadow", "/etc/password" ]`,
   579  		model,
   580  		pc,
   581  		opts,
   582  	)
   583  	if err != nil {
   584  		t.Fatal(err)
   585  	}
   586  	opts.MacroStore.Add(macro)
   587  
   588  	expr := `"/etc/shadow" in list`
   589  	rule, err := parseRule(expr, model, opts)
   590  	if err != nil {
   591  		t.Fatalf("error while evaluating `%s`: %s", expr, err)
   592  	}
   593  
   594  	ctx := NewContext(&testEvent{})
   595  
   596  	if !rule.Eval(ctx) {
   597  		t.Fatalf("should return true")
   598  	}
   599  }
   600  
   601  func TestMacroExpression(t *testing.T) {
   602  	model := &testModel{}
   603  	pc := ast.NewParsingContext()
   604  	opts := newOptsWithParams(make(map[string]interface{}), nil)
   605  
   606  	macro, err := NewMacro(
   607  		"is_passwd",
   608  		`open.filename in [ "/etc/shadow", "/etc/passwd" ]`,
   609  		model,
   610  		pc,
   611  		opts,
   612  	)
   613  	if err != nil {
   614  		t.Fatal(err)
   615  	}
   616  	opts.MacroStore.Add(macro)
   617  
   618  	event := &testEvent{
   619  		process: testProcess{
   620  			name: "httpd",
   621  		},
   622  		open: testOpen{
   623  			filename: "/etc/passwd",
   624  		},
   625  	}
   626  
   627  	expr := `process.name == "httpd" && is_passwd`
   628  
   629  	rule, err := parseRule(expr, model, opts)
   630  	if err != nil {
   631  		t.Fatalf("error while evaluating `%s`: %s", expr, err)
   632  	}
   633  
   634  	ctx := NewContext(event)
   635  	if !rule.Eval(ctx) {
   636  		t.Fatalf("should return true")
   637  	}
   638  }
   639  
   640  func TestMacroPartial(t *testing.T) {
   641  	model := &testModel{}
   642  	pc := ast.NewParsingContext()
   643  	opts := newOptsWithParams(make(map[string]interface{}), nil)
   644  
   645  	macro, err := NewMacro(
   646  		"is_passwd",
   647  		`open.filename in [ "/etc/shadow", "/etc/passwd" ]`,
   648  		model,
   649  		pc,
   650  		opts,
   651  	)
   652  	if err != nil {
   653  		t.Fatal(err)
   654  	}
   655  	opts.MacroStore.Add(macro)
   656  
   657  	event := &testEvent{
   658  		process: testProcess{
   659  			name: "httpd",
   660  		},
   661  		open: testOpen{
   662  			filename: "/etc/passwd",
   663  		},
   664  	}
   665  
   666  	expr := `process.name == "httpd" && is_passwd`
   667  
   668  	rule, err := parseRule(expr, model, opts)
   669  	if err != nil {
   670  		t.Fatalf("error while evaluating `%s`: %s", expr, err)
   671  	}
   672  
   673  	ctx := NewContext(event)
   674  
   675  	result, err := rule.PartialEval(ctx, "open.filename")
   676  	if err != nil {
   677  		t.Fatalf("error while partial evaluating `%s` : %s", expr, err)
   678  	}
   679  
   680  	if !result {
   681  		t.Fatal("open.filename should be a discarder")
   682  	}
   683  
   684  	event.open.filename = "abc"
   685  	result, err = rule.PartialEval(ctx, "open.filename")
   686  	if err != nil {
   687  		t.Fatalf("error while partial evaluating `%s` : %s", expr, err)
   688  	}
   689  
   690  	if result {
   691  		t.Fatal("open.filename should be a discarder")
   692  	}
   693  }
   694  
   695  func TestNestedMacros(t *testing.T) {
   696  	event := &testEvent{
   697  		open: testOpen{
   698  			filename: "/etc/passwd",
   699  		},
   700  	}
   701  
   702  	model := &testModel{}
   703  	pc := ast.NewParsingContext()
   704  	opts := newOptsWithParams(make(map[string]interface{}), nil)
   705  
   706  	macro1, err := NewMacro(
   707  		"sensitive_files",
   708  		`[ "/etc/shadow", "/etc/passwd" ]`,
   709  		model,
   710  		pc,
   711  		opts,
   712  	)
   713  	if err != nil {
   714  		t.Fatal(err)
   715  	}
   716  	opts.MacroStore.Add(macro1)
   717  
   718  	macro2, err := NewMacro(
   719  		"is_sensitive_opened",
   720  		`open.filename in sensitive_files`,
   721  		model,
   722  		pc,
   723  		opts,
   724  	)
   725  	if err != nil {
   726  		t.Fatal(err)
   727  	}
   728  	opts.MacroStore.Add(macro2)
   729  
   730  	rule, err := parseRule(macro2.ID, model, opts)
   731  	if err != nil {
   732  		t.Fatalf("error while evaluating `%s`: %s", macro2.ID, err)
   733  	}
   734  
   735  	ctx := NewContext(event)
   736  	if !rule.Eval(ctx) {
   737  		t.Fatalf("should return true")
   738  	}
   739  }
   740  
   741  func TestFieldValidator(t *testing.T) {
   742  	expr := `process.uid == -100 && open.filename == "/etc/passwd"`
   743  
   744  	opts := newOptsWithParams(nil, nil)
   745  
   746  	if _, err := parseRule(expr, &testModel{}, opts); err == nil {
   747  		t.Error("expected an error on process.uid being negative")
   748  	}
   749  }
   750  
   751  func TestLegacyField(t *testing.T) {
   752  	model := &testModel{}
   753  
   754  	opts := newOptsWithParams(nil, legacyFields)
   755  
   756  	tests := []struct {
   757  		Expr     string
   758  		Expected bool
   759  	}{
   760  		{Expr: `process.legacy_name == "/tmp/secrets"`, Expected: true},
   761  		{Expr: `process.random_name == "/tmp/secrets"`, Expected: false},
   762  		{Expr: `process.name == "/tmp/secrets"`, Expected: true},
   763  	}
   764  
   765  	for _, test := range tests {
   766  		_, err := parseRule(test.Expr, model, opts)
   767  		if err == nil != test.Expected {
   768  			t.Errorf("expected result `%t` not found, got `%t`\n%s", test.Expected, err == nil, test.Expr)
   769  		}
   770  	}
   771  }
   772  
   773  func TestRegisterSyntaxError(t *testing.T) {
   774  	model := &testModel{}
   775  
   776  	opts := newOptsWithParams(nil, nil)
   777  
   778  	tests := []struct {
   779  		Expr     string
   780  		Expected bool
   781  	}{
   782  		{Expr: `process.list[_].key == 10 && process.list[_].value == "AAA"`, Expected: true},
   783  		{Expr: `process.list[].key == 10 && process.list.value == "AAA"`, Expected: false},
   784  		{Expr: `process.list[_].key == 10 && process.list.value == "AAA"`, Expected: true},
   785  		{Expr: `process.list.key[] == 10 && process.list.value == "AAA"`, Expected: false},
   786  		{Expr: `process[].list.key == 10 && process.list.value == "AAA"`, Expected: false},
   787  		{Expr: `[]process.list.key == 10 && process.list.value == "AAA"`, Expected: false},
   788  		//{Expr: `process.list[A].key == 10 && process.list[A].value == "AAA" && process.array[B].key == 10 && process.array[B].value == "AAA"`, Expected: false},
   789  	}
   790  
   791  	for _, test := range tests {
   792  		_, err := parseRule(test.Expr, model, opts)
   793  		if err == nil != test.Expected {
   794  			t.Errorf("expected result `%t` not found, got `%t`\n%s", test.Expected, err == nil, test.Expr)
   795  		}
   796  	}
   797  }
   798  
   799  func TestRegister(t *testing.T) {
   800  	event := &testEvent{
   801  		process: testProcess{},
   802  	}
   803  
   804  	event.process.list = list.New()
   805  	event.process.list.PushBack(&testItem{key: 10, value: "AAA"})
   806  	event.process.list.PushBack(&testItem{key: 100, value: "BBB"})
   807  	event.process.list.PushBack(&testItem{key: 200, value: "CCC"})
   808  
   809  	event.process.array = []*testItem{
   810  		{key: 1000, value: "EEEE", flag: true},
   811  		{key: 1002, value: "DDDD", flag: false},
   812  	}
   813  
   814  	tests := []struct {
   815  		Expr     string
   816  		Expected bool
   817  	}{
   818  		{Expr: `process.list[_].key == 10`, Expected: true},
   819  		{Expr: `process.list[_].key == 9999`, Expected: false},
   820  		{Expr: `process.list[_].key != 10`, Expected: false},
   821  		{Expr: `process.list[_].key != 9999`, Expected: true},
   822  
   823  		{Expr: `process.list[_].key >= 200`, Expected: true},
   824  		{Expr: `process.list[_].key > 100`, Expected: true},
   825  		{Expr: `process.list[_].key <= 200`, Expected: true},
   826  		{Expr: `process.list[_].key < 100`, Expected: true},
   827  
   828  		{Expr: `10 == process.list[_].key`, Expected: true},
   829  		{Expr: `9999 == process.list[_].key`, Expected: false},
   830  		{Expr: `10 != process.list[_].key`, Expected: false},
   831  		{Expr: `9999 != process.list[_].key`, Expected: true},
   832  
   833  		{Expr: `9999 in process.list[_].key`, Expected: false},
   834  		{Expr: `9999 not in process.list[_].key`, Expected: true},
   835  		{Expr: `10 in process.list[_].key`, Expected: true},
   836  		{Expr: `10 not in process.list[_].key`, Expected: false},
   837  
   838  		{Expr: `process.list[_].key > 10`, Expected: true},
   839  		{Expr: `process.list[_].key > 9999`, Expected: false},
   840  		{Expr: `process.list[_].key < 10`, Expected: false},
   841  		{Expr: `process.list[_].key < 9999`, Expected: true},
   842  
   843  		{Expr: `5 < process.list[_].key`, Expected: true},
   844  		{Expr: `9999 < process.list[_].key`, Expected: false},
   845  		{Expr: `10 > process.list[_].key`, Expected: false},
   846  		{Expr: `9999 > process.list[_].key`, Expected: true},
   847  
   848  		{Expr: `true in process.array[_].flag`, Expected: true},
   849  		{Expr: `false not in process.array[_].flag`, Expected: false},
   850  
   851  		{Expr: `process.array[_].flag == true`, Expected: true},
   852  		{Expr: `process.array[_].flag != false`, Expected: false},
   853  
   854  		{Expr: `"AAA" in process.list[_].value`, Expected: true},
   855  		{Expr: `"ZZZ" in process.list[_].value`, Expected: false},
   856  		{Expr: `"AAA" not in process.list[_].value`, Expected: false},
   857  		{Expr: `"ZZZ" not in process.list[_].value`, Expected: true},
   858  
   859  		{Expr: `~"AA*" in process.list[_].value`, Expected: true},
   860  		{Expr: `~"ZZ*" in process.list[_].value`, Expected: false},
   861  		{Expr: `~"AA*" not in process.list[_].value`, Expected: false},
   862  		{Expr: `~"ZZ*" not in process.list[_].value`, Expected: true},
   863  
   864  		{Expr: `r"[A]{1,3}" in process.list[_].value`, Expected: true},
   865  		{Expr: `process.list[_].value in [r"[A]{1,3}", "nnnnn"]`, Expected: true},
   866  
   867  		{Expr: `process.list[_].value == ~"AA*"`, Expected: true},
   868  		{Expr: `process.list[_].value == ~"ZZ*"`, Expected: false},
   869  		{Expr: `process.list[_].value != ~"AA*"`, Expected: false},
   870  		{Expr: `process.list[_].value != ~"ZZ*"`, Expected: true},
   871  
   872  		{Expr: `process.list[_].value =~ "AA*"`, Expected: true},
   873  		{Expr: `process.list[_].value =~ "ZZ*"`, Expected: false},
   874  		{Expr: `process.list[_].value !~ "AA*"`, Expected: false},
   875  		{Expr: `process.list[_].value !~ "ZZ*"`, Expected: true},
   876  
   877  		{Expr: `process.list[_].value in ["~zzzz", ~"AA*", "nnnnn"]`, Expected: true},
   878  		{Expr: `process.list[_].value in ["~zzzz", ~"AA*", "nnnnn"]`, Expected: true},
   879  		{Expr: `process.list[_].value in ["~zzzz", "AAA", "nnnnn"]`, Expected: true},
   880  		{Expr: `process.list[_].value in ["~zzzz", "AA*", "nnnnn"]`, Expected: false},
   881  
   882  		{Expr: `process.list[_].value in [~"ZZ*", "nnnnn"]`, Expected: false},
   883  		{Expr: `process.list[_].value not in [~"AA*", "nnnnn"]`, Expected: false},
   884  		{Expr: `process.list[_].value not in [~"ZZ*", "nnnnn"]`, Expected: true},
   885  		{Expr: `process.list[_].value not in [~"ZZ*", "AAA", "nnnnn"]`, Expected: false},
   886  		{Expr: `process.list[_].value not in [~"ZZ*", ~"AA*", "nnnnn"]`, Expected: false},
   887  
   888  		{Expr: `process.list[_].key == 10 && process.list[_].value == "AAA"`, Expected: true},
   889  		{Expr: `process.list[_].key == 9999 && process.list[_].value == "AAA"`, Expected: false},
   890  		{Expr: `process.list[_].key == 100 && process.list[_].value == "BBB"`, Expected: true},
   891  		{Expr: `process.list[_].key == 200 && process.list[_].value == "CCC"`, Expected: true},
   892  		{Expr: `process.list.key == 200 && process.list.value == "AAA"`, Expected: true},
   893  		{Expr: `process.list[_].key == 10 && process.list.value == "AAA"`, Expected: true},
   894  
   895  		{Expr: `process.array[_].key == 1000 && process.array[_].value == "EEEE"`, Expected: true},
   896  		{Expr: `process.array[_].key == 1002 && process.array[_].value == "EEEE"`, Expected: true},
   897  	}
   898  
   899  	for _, test := range tests {
   900  		result, _, err := eval(t, event, test.Expr)
   901  		if err != nil {
   902  			t.Fatalf("error while evaluating `%s`: %s", test.Expr, err)
   903  		}
   904  
   905  		if result != test.Expected {
   906  			t.Errorf("expected result `%t` not found, got `%t`\n%s", test.Expected, result, test.Expr)
   907  		}
   908  	}
   909  }
   910  
   911  func TestRegisterPartial(t *testing.T) {
   912  	event := &testEvent{
   913  		process: testProcess{},
   914  	}
   915  
   916  	event.process.list = list.New()
   917  	event.process.list.PushBack(&testItem{key: 10, value: "AA"})
   918  	event.process.list.PushBack(&testItem{key: 100, value: "BBB"})
   919  	event.process.list.PushBack(&testItem{key: 200, value: "CCC"})
   920  
   921  	event.process.array = []*testItem{
   922  		{key: 1000, value: "EEEE"},
   923  		{key: 1002, value: "DDDD"},
   924  	}
   925  
   926  	tests := []struct {
   927  		Expr        string
   928  		Field       Field
   929  		IsDiscarder bool
   930  	}{
   931  		{Expr: `process.list[_].key == 10 && process.list[_].value == "AA"`, Field: "process.list.key", IsDiscarder: false},
   932  		{Expr: `process.list[_].key == 55 && process.list[_].value == "AA"`, Field: "process.list.key", IsDiscarder: true},
   933  		{Expr: `process.list[_].key == 55 && process.list[_].value == "AA"`, Field: "process.list.value", IsDiscarder: false},
   934  		{Expr: `process.list[_].key == 10 && process.list[_].value == "ZZZ"`, Field: "process.list.value", IsDiscarder: true},
   935  		//{Expr: `process.list[A].key == 10 && process.list[B].value == "ZZZ"`, Field: "process.list.key", IsDiscarder: false},
   936  		//{Expr: `process.list[A].key == 55 && process.list[B].value == "AA"`, Field: "process.list.key", IsDiscarder: true},
   937  	}
   938  
   939  	ctx := NewContext(event)
   940  
   941  	for _, test := range tests {
   942  		model := &testModel{}
   943  
   944  		opts := newOptsWithParams(testConstants, nil)
   945  
   946  		rule, err := parseRule(test.Expr, model, opts)
   947  		if err != nil {
   948  			t.Fatalf("error while evaluating `%s`: %s", test.Expr, err)
   949  		}
   950  
   951  		result, err := rule.PartialEval(ctx, test.Field)
   952  		if err != nil {
   953  			t.Fatalf("error while partial evaluating `%s` for `%s`: %s", test.Expr, test.Field, err)
   954  		}
   955  
   956  		if !result != test.IsDiscarder {
   957  			t.Fatalf("expected result `%t` for `%s`, got `%t`\n%s", test.IsDiscarder, test.Field, result, test.Expr)
   958  		}
   959  	}
   960  }
   961  
   962  func TestOptimizer(t *testing.T) {
   963  	event := &testEvent{
   964  		process: testProcess{
   965  			uid: 44,
   966  			gid: 44,
   967  		},
   968  	}
   969  
   970  	event.process.list = list.New()
   971  	event.process.list.PushBack(&testItem{key: 10, value: "AA"})
   972  
   973  	tests := []struct {
   974  		Expr      string
   975  		Evaluated func() bool
   976  	}{
   977  		{Expr: `process.list[_].key == 44 && process.gid == 55`, Evaluated: func() bool { return event.listEvaluated }},
   978  		{Expr: `process.gid == 55 && process.list[_].key == 44`, Evaluated: func() bool { return event.listEvaluated }},
   979  		{Expr: `process.uid in [66, 77, 88] && process.gid == 55`, Evaluated: func() bool { return event.uidEvaluated }},
   980  		{Expr: `process.gid == 55 && process.uid in [66, 77, 88]`, Evaluated: func() bool { return event.uidEvaluated }},
   981  	}
   982  
   983  	for _, test := range tests {
   984  		_, _, err := eval(t, event, test.Expr)
   985  		if err != nil {
   986  			t.Fatalf("error while evaluating: %s", err)
   987  		}
   988  
   989  		if test.Evaluated() {
   990  			t.Fatalf("not optimized: %s", test.Expr)
   991  		}
   992  	}
   993  }
   994  
   995  func TestDuration(t *testing.T) {
   996  	// time reliability issue
   997  	if runtime.GOARCH == "386" && runtime.GOOS == "windows" {
   998  		t.Skip()
   999  	}
  1000  
  1001  	event := &testEvent{
  1002  		process: testProcess{
  1003  			createdAt: time.Now().UnixNano(),
  1004  		},
  1005  	}
  1006  
  1007  	tests := []struct {
  1008  		Expr     string
  1009  		Expected bool
  1010  	}{
  1011  		{Expr: `process.created_at < 2s`, Expected: true},
  1012  		{Expr: `process.created_at > 2s`, Expected: false},
  1013  	}
  1014  
  1015  	for _, test := range tests {
  1016  		result, _, err := eval(t, event, test.Expr)
  1017  		if err != nil {
  1018  			t.Fatalf("error while evaluating `%s`: %s", test.Expr, err)
  1019  		}
  1020  
  1021  		if result != test.Expected {
  1022  			t.Errorf("expected result `%t` not found, got `%t`\nnow: %v, create_at: %v\n%s", test.Expected, result, time.Now().UnixNano(), event.process.createdAt, test.Expr)
  1023  		}
  1024  	}
  1025  
  1026  	time.Sleep(4 * time.Second)
  1027  
  1028  	tests = []struct {
  1029  		Expr     string
  1030  		Expected bool
  1031  	}{
  1032  		{Expr: `process.created_at < 2s`, Expected: false},
  1033  		{Expr: `process.created_at > 2s`, Expected: true},
  1034  	}
  1035  
  1036  	for _, test := range tests {
  1037  		result, _, err := eval(t, event, test.Expr)
  1038  		if err != nil {
  1039  			t.Fatalf("error while evaluating `%s`: %s", test.Expr, err)
  1040  		}
  1041  
  1042  		if result != test.Expected {
  1043  			t.Errorf("expected result `%t` not found, got `%t`\nnow: %v, create_at: %v\n%s", test.Expected, result, time.Now().UnixNano(), event.process.createdAt, test.Expr)
  1044  		}
  1045  	}
  1046  }
  1047  
  1048  func parseCIDR(t *testing.T, ip string) net.IPNet {
  1049  	ipnet, err := ParseCIDR(ip)
  1050  	if err != nil {
  1051  		t.Error(err)
  1052  	}
  1053  	return *ipnet
  1054  }
  1055  
  1056  func TestIPv4(t *testing.T) {
  1057  	_, cidr, _ := net.ParseCIDR("192.168.0.1/24")
  1058  	var cidrs []net.IPNet
  1059  	for _, cidrStr := range []string{"192.168.0.1/24", "10.0.0.1/16"} {
  1060  		_, cidrTmp, _ := net.ParseCIDR(cidrStr)
  1061  		cidrs = append(cidrs, *cidrTmp)
  1062  	}
  1063  
  1064  	event := &testEvent{
  1065  		network: testNetwork{
  1066  			ip:    parseCIDR(t, "192.168.0.1"),
  1067  			ips:   []net.IPNet{parseCIDR(t, "192.168.0.1"), parseCIDR(t, "192.169.0.1")},
  1068  			cidr:  *cidr,
  1069  			cidrs: cidrs,
  1070  		},
  1071  	}
  1072  
  1073  	tests := []struct {
  1074  		Expr     string
  1075  		Expected bool
  1076  	}{
  1077  		{Expr: `192.168.0.1 == 192.168.0.1`, Expected: true},
  1078  		{Expr: `192.168.0.1 == 192.168.0.2`, Expected: false},
  1079  		{Expr: `192.168.0.15 in 192.168.0.1/24`, Expected: true},
  1080  		{Expr: `192.168.0.16 not in 192.168.1.1/24`, Expected: true},
  1081  		{Expr: `192.168.0.16/16 in 192.168.1.1/8`, Expected: true},
  1082  		{Expr: `192.168.0.16/16 allin 192.168.1.1/8`, Expected: true},
  1083  		{Expr: `193.168.0.16/16 in 192.168.1.1/8`, Expected: false},
  1084  		{Expr: `network.ip == 192.168.0.1`, Expected: true},
  1085  		{Expr: `network.ip == 127.0.0.1`, Expected: false},
  1086  		{Expr: `network.ip == ::ffff:192.168.0.1`, Expected: true},
  1087  		{Expr: `network.ip == ::ffff:127.0.0.1`, Expected: false},
  1088  		{Expr: `network.ip in 192.168.0.1/32`, Expected: true},
  1089  		{Expr: `network.ip in 0.0.0.0/0`, Expected: true},
  1090  		{Expr: `network.ip in ::1/0`, Expected: false},
  1091  		{Expr: `network.ip in 192.168.4.0/16`, Expected: true},
  1092  		{Expr: `network.ip in 192.168.4.0/24`, Expected: false},
  1093  		{Expr: `network.ip not in 192.168.4.0/16`, Expected: false},
  1094  		{Expr: `network.ip not in 192.168.4.0/24`, Expected: true},
  1095  		{Expr: `network.ip in ::ffff:192.168.4.0/112`, Expected: true},
  1096  		{Expr: `network.ip in ::ffff:192.168.4.0/120`, Expected: false},
  1097  		{Expr: `network.ip in [ 127.0.0.1, 192.168.0.1, 10.0.0.1 ]`, Expected: true},
  1098  		{Expr: `network.ip in [ 127.0.0.1, 10.0.0.1 ]`, Expected: false},
  1099  		{Expr: `network.ip in [ 192.168.4.1/16, 10.0.0.1/32 ]`, Expected: true},
  1100  		{Expr: `network.ip in [ 10.0.0.1, 127.0.0.1, 192.169.4.1/16 ]`, Expected: false},
  1101  		{Expr: `network.ip in [ 10.0.0.1, 127.0.0.1, 192.169.4.1/16, ::ffff:192.168.0.1/128 ]`, Expected: true},
  1102  		{Expr: `192.168.0.1 in [ 10.0.0.1, 127.0.0.1, 192.169.4.1/16, ::ffff:192.168.0.1/128 ]`, Expected: true},
  1103  		{Expr: `192.168.0.1/24 in [ 10.0.0.1, 127.0.0.1, 192.169.4.1/16, ::ffff:192.168.0.1/120 ]`, Expected: true},
  1104  		{Expr: `192.168.0.1/24 allin [ 10.0.0.1, 127.0.0.1, 192.169.4.1/16, ::ffff:192.168.0.1/120 ]`, Expected: true},
  1105  
  1106  		{Expr: `network.ips in 192.168.0.0/16`, Expected: true},
  1107  		{Expr: `network.ips not in 192.168.0.0/16`, Expected: false},
  1108  		{Expr: `network.ips allin 192.168.0.0/16`, Expected: false},
  1109  		{Expr: `network.ips allin 192.168.0.0/8`, Expected: true},
  1110  		{Expr: `network.ips in [ 192.168.0.0/32, 193.168.0.0/16, ::ffff:192.168.0.1 ]`, Expected: true},
  1111  		{Expr: `network.ips not in [ 192.168.0.0/32, 193.168.0.0/16 ]`, Expected: true},
  1112  		{Expr: `network.ips allin [ 192.168.0.0/8, 0.0.0.0/0 ]`, Expected: true},
  1113  		{Expr: `network.ips allin [ 192.168.0.0/8, 1.0.0.0/8 ]`, Expected: false},
  1114  		{Expr: `192.0.0.0/8 allin network.ips`, Expected: true},
  1115  
  1116  		{Expr: `network.cidr in 192.168.0.0/8`, Expected: true},
  1117  		{Expr: `network.cidr in 193.168.0.0/8`, Expected: false},
  1118  		{Expr: `network.cidrs in 10.0.0.1/8`, Expected: true},
  1119  		{Expr: `network.cidrs allin 10.0.0.1/8`, Expected: false},
  1120  	}
  1121  
  1122  	for _, test := range tests {
  1123  		result, _, err := eval(t, event, test.Expr)
  1124  		if err != nil {
  1125  			t.Fatalf("error while evaluating `%s`: %s", test.Expr, err)
  1126  		}
  1127  
  1128  		if result != test.Expected {
  1129  			t.Errorf("expected result `%v` not found, got `%v`, expression: %s", test.Expected, result, test.Expr)
  1130  		}
  1131  	}
  1132  }
  1133  
  1134  func TestIPv6(t *testing.T) {
  1135  	_, cidr, _ := net.ParseCIDR("2001:0:0eab:dead::a0:abcd:4e/112")
  1136  	var cidrs []net.IPNet
  1137  	for _, cidrStr := range []string{"2001:0:0eab:dead::a0:abcd:4e/112", "2001:0:0eab:c00f::a0:abcd:4e/64"} {
  1138  		_, cidrTmp, _ := net.ParseCIDR(cidrStr)
  1139  		cidrs = append(cidrs, *cidrTmp)
  1140  	}
  1141  	event := &testEvent{
  1142  		network: testNetwork{
  1143  			ip:    parseCIDR(t, "2001:0:0eab:dead::a0:abcd:4e"),
  1144  			ips:   []net.IPNet{parseCIDR(t, "2001:0:0eab:dead::a0:abcd:4e"), parseCIDR(t, "2001:0:0eab:dead::a0:abce:4e")},
  1145  			cidr:  *cidr,
  1146  			cidrs: cidrs,
  1147  		},
  1148  	}
  1149  
  1150  	tests := []struct {
  1151  		Expr     string
  1152  		Expected bool
  1153  	}{
  1154  		{Expr: `2001:0:0eab:dead::a0:abcd:4e == 2001:0:0eab:dead::a0:abcd:4e`, Expected: true},
  1155  		{Expr: `2001:0:0eab:dead::a0:abcd:4e == 2001:0:0eab:dead::a0:abcd:4f`, Expected: false},
  1156  		{Expr: `2001:0:0eab:dead::a0:abcd:4e in 2001:0:0eab:dead::a0:abcd:0/120`, Expected: true},
  1157  		{Expr: `2001:0:0eab:dead::a0:abcd:4e not in 2001:0:0eab:dead::a0:abcd:ab00/120`, Expected: true},
  1158  		{Expr: `2001:0:0eab:dead::a0:abcd:4e/64 in 2001:0:0eab:dead::a0:abcd:1b00/32`, Expected: true},
  1159  		{Expr: `2001:0:0eab:dead::a0:abcd:4e/64 allin 2001:0:0eab:dead::a0:abcd:1b00/32`, Expected: true},
  1160  		{Expr: `2001:0:0eab:dead::a0:abcd:4e/64 in [ 2001:0:0eab:dead::a0:abcd:1b00/32 ]`, Expected: true},
  1161  		{Expr: `2001:0:0eab:dead::a0:abcd:4e/32 in [ 2001:0:0eab:dead::a0:abcd:1b00/64 ]`, Expected: true},
  1162  		{Expr: `network.ip == 2001:0:0eab:dead::a0:abcd:4e`, Expected: true},
  1163  		{Expr: `network.ip == ::1`, Expected: false},
  1164  		{Expr: `network.ip == 127.0.0.1`, Expected: false},
  1165  		{Expr: `network.ip in 0.0.0.0/0`, Expected: false},
  1166  		{Expr: `network.ip in ::1/0`, Expected: true},
  1167  		{Expr: `network.ip in 2001:0:0eab:dead::a0:abcd:4e/128`, Expected: true},
  1168  		{Expr: `network.ip in 2001:0:0eab:dead::a0:abcd:0/112`, Expected: true},
  1169  		{Expr: `network.ip in 2001:0:0eab:dead::a0:0:0/112`, Expected: false},
  1170  		{Expr: `network.ip not in 2001:0:0eab:dead::a0:0:0/112`, Expected: true},
  1171  		{Expr: `network.ip in [ ::1, 2001:0:0eab:dead::a0:abcd:4e, 2001:0:0eab:dead::a0:abcd:4f ]`, Expected: true},
  1172  		{Expr: `network.ip in [ ::1, 2001:0:0eab:dead::a0:abcd:4f ]`, Expected: false},
  1173  		{Expr: `network.ip in [ 2001:0:0eab:dead::a0:abcd:0/112, 2001:0:0eab:dead::a0:abcd:4f/128 ]`, Expected: true},
  1174  		{Expr: `network.ip in [ ::1, 2001:124:0eab:dead::a0:abcd:4f, 2001:0:0eab:dead::a0:abcd:0/112 ]`, Expected: true},
  1175  		{Expr: `2001:0:0eab:dead::a0:abcd:4e in [ 2001:0:0eab:dead::a0:abcd:4e, ::1, 2002:0:0eab:dead::/64, ::ffff:192.168.0.1/128 ]`, Expected: true},
  1176  		{Expr: `2001:0:0eab:dead::a0:abcd:4e/64 in [ 10.0.0.1, 127.0.0.1, 2001:0:0eab:dead::a0:abcd:1b00/32, ::ffff:192.168.0.1/120 ]`, Expected: true},
  1177  		{Expr: `2001:0:0eab:dead::a0:abcd:4e/64 allin [ 10.0.0.1, 127.0.0.1, 2001:0:0eab:dead::a0:abcd:1b00/32, ::ffff:192.168.0.1/120 ]`, Expected: true},
  1178  
  1179  		{Expr: `network.ips in 2001:0:0eab:dead::a0:abcd:0/120`, Expected: true},
  1180  		{Expr: `network.ips not in 2001:0:0eab:dead::a0:abcd:0/120`, Expected: false},
  1181  		{Expr: `network.ips allin 2001:0:0eab:dead::a0:abcd:0/120`, Expected: false},
  1182  		{Expr: `network.ips allin 2001:0:0eab:dead::a0:abcd:0/104`, Expected: true},
  1183  		{Expr: `network.ips in [ 2001:0:0eab:dead::a0:abcd:0/128, 2001:0:0eab:dead::a0:abcd:0/120, 2001:0:0eab:dead::a0:abce:4e ]`, Expected: true},
  1184  		{Expr: `network.ips not in [ 2001:0:0eab:dead::a0:abcd:0/128, 2001:0:0eab:dead::a0:abcf:4e/120 ]`, Expected: true},
  1185  		{Expr: `network.ips allin [ 2001:0:0eab:dead::a0:abcd:0/104, 2001::1/16 ]`, Expected: true},
  1186  		{Expr: `network.ips allin [ 2001:0:0eab:dead::a0:abcd:0/104, 2002::1/16 ]`, Expected: false},
  1187  		{Expr: `2001:0:0eab:dead::a0:abcd:0/104 allin network.ips`, Expected: true},
  1188  
  1189  		{Expr: `network.cidr in 2001:0:0eab:dead::a0:abcd:4e/112`, Expected: true},
  1190  		{Expr: `network.cidr in 2002:0:0eab:dead::a0:abcd:4e/72`, Expected: false},
  1191  		{Expr: `network.cidrs in 2001:0:0eab:dead::a0:abcd:4e/64`, Expected: true},
  1192  		{Expr: `network.cidrs allin 2001:0:0eab:dead::a0:abcd:4e/64`, Expected: false},
  1193  	}
  1194  
  1195  	for _, test := range tests {
  1196  		result, _, err := eval(t, event, test.Expr)
  1197  		if err != nil {
  1198  			t.Fatalf("error while evaluating `%s`: %s", test.Expr, err)
  1199  		}
  1200  
  1201  		if result != test.Expected {
  1202  			t.Errorf("expected result `%v` not found, got `%v`, expression: %s", test.Expected, result, test.Expr)
  1203  		}
  1204  	}
  1205  }
  1206  
  1207  func TestOpOverrides(t *testing.T) {
  1208  	event := &testEvent{
  1209  		process: testProcess{
  1210  			orName: "abc",
  1211  		},
  1212  	}
  1213  
  1214  	// values that will be returned by the operator override
  1215  	event.process.orNameValues = func() *StringValues {
  1216  		var values StringValues
  1217  		values.AppendScalarValue("abc")
  1218  
  1219  		if err := values.Compile(DefaultStringCmpOpts); err != nil {
  1220  			return nil
  1221  		}
  1222  
  1223  		return &values
  1224  	}
  1225  
  1226  	event.process.orArray = []*testItem{
  1227  		{key: 1000, value: "abc", flag: true},
  1228  	}
  1229  
  1230  	// values that will be returned by the operator override
  1231  	event.process.orArrayValues = func() *StringValues {
  1232  		var values StringValues
  1233  		values.AppendScalarValue("abc")
  1234  
  1235  		if err := values.Compile(DefaultStringCmpOpts); err != nil {
  1236  			return nil
  1237  		}
  1238  
  1239  		return &values
  1240  	}
  1241  
  1242  	tests := []struct {
  1243  		Expr     string
  1244  		Expected bool
  1245  	}{
  1246  		{Expr: `process.or_name == "not"`, Expected: true},
  1247  		{Expr: `process.or_name != "not"`, Expected: false},
  1248  		{Expr: `process.or_name in ["not"]`, Expected: true},
  1249  		{Expr: `process.or_array.value == "not"`, Expected: true},
  1250  		{Expr: `process.or_array.value in ["not"]`, Expected: true},
  1251  		{Expr: `process.or_array.value not in ["not"]`, Expected: false},
  1252  	}
  1253  
  1254  	for _, test := range tests {
  1255  		result, _, err := eval(t, event, test.Expr)
  1256  		if err != nil {
  1257  			t.Fatalf("error while evaluating `%s`: %s", test.Expr, err)
  1258  		}
  1259  
  1260  		if result != test.Expected {
  1261  			t.Errorf("expected result `%t` not found, got `%t`\n%s", test.Expected, result, test.Expr)
  1262  		}
  1263  	}
  1264  }
  1265  
  1266  func TestOpOverridePartials(t *testing.T) {
  1267  	event := &testEvent{
  1268  		process: testProcess{
  1269  			orName: "abc",
  1270  		},
  1271  	}
  1272  
  1273  	// values that will be returned by the operator override
  1274  	event.process.orNameValues = func() *StringValues {
  1275  		var values StringValues
  1276  		values.AppendScalarValue("abc")
  1277  
  1278  		if err := values.Compile(DefaultStringCmpOpts); err != nil {
  1279  			return nil
  1280  		}
  1281  
  1282  		return &values
  1283  	}
  1284  
  1285  	event.process.orArray = []*testItem{
  1286  		{key: 1000, value: "abc", flag: true},
  1287  	}
  1288  
  1289  	// values that will be returned by the operator override
  1290  	event.process.orArrayValues = func() *StringValues {
  1291  		var values StringValues
  1292  		values.AppendScalarValue("abc")
  1293  
  1294  		if err := values.Compile(DefaultStringCmpOpts); err != nil {
  1295  			return nil
  1296  		}
  1297  
  1298  		return &values
  1299  	}
  1300  
  1301  	tests := []struct {
  1302  		Expr        string
  1303  		Field       string
  1304  		IsDiscarder bool
  1305  	}{
  1306  		{Expr: `process.or_name == "not"`, Field: "process.or_name", IsDiscarder: false},
  1307  		{Expr: `process.or_name != "not"`, Field: "process.or_name", IsDiscarder: true},
  1308  		{Expr: `process.or_name != "not" || true`, Field: "process.or_name", IsDiscarder: false},
  1309  		{Expr: `process.or_name in ["not"]`, Field: "process.or_name", IsDiscarder: false},
  1310  		{Expr: `process.or_array.value == "not"`, Field: "process.or_array.value", IsDiscarder: false},
  1311  		{Expr: `process.or_array.value in ["not"]`, Field: "process.or_array.value", IsDiscarder: false},
  1312  		{Expr: `process.or_array.value not in ["not"]`, Field: "process.or_array.value", IsDiscarder: true},
  1313  		{Expr: `process.or_array.value not in ["not"] || true`, Field: "process.or_array.value", IsDiscarder: false},
  1314  	}
  1315  
  1316  	ctx := NewContext(event)
  1317  
  1318  	for _, test := range tests {
  1319  		model := &testModel{}
  1320  
  1321  		opts := newOptsWithParams(testConstants, nil)
  1322  
  1323  		rule, err := parseRule(test.Expr, model, opts)
  1324  		if err != nil {
  1325  			t.Fatalf("error while evaluating `%s`: %s", test.Expr, err)
  1326  		}
  1327  
  1328  		result, err := rule.PartialEval(ctx, test.Field)
  1329  		if err != nil {
  1330  			t.Fatalf("error while partial evaluating `%s` for `%s`: %s", test.Expr, test.Field, err)
  1331  		}
  1332  
  1333  		if !result != test.IsDiscarder {
  1334  			t.Fatalf("expected result `%t` for `%s`, got `%t`\n%s", test.IsDiscarder, test.Field, result, test.Expr)
  1335  		}
  1336  	}
  1337  }
  1338  
  1339  func TestFieldValues(t *testing.T) {
  1340  	tests := []struct {
  1341  		Expr     string
  1342  		Field    string
  1343  		Expected FieldValue
  1344  	}{
  1345  		{Expr: `process.name == "/proc/1/maps"`, Field: "process.name", Expected: FieldValue{Value: "/proc/1/maps", Type: ScalarValueType}},
  1346  		{Expr: `process.name =~ "/proc/1/*"`, Field: "process.name", Expected: FieldValue{Value: "/proc/1/*", Type: GlobValueType}},
  1347  		{Expr: `process.name =~ r"/proc/1/.*"`, Field: "process.name", Expected: FieldValue{Value: "/proc/1/.*", Type: RegexpValueType}},
  1348  		{Expr: `process.name == "/proc/${pid}/maps"`, Field: "process.name", Expected: FieldValue{Value: "/proc/${pid}/maps", Type: VariableValueType}},
  1349  		{Expr: `open.filename =~ "/proc/1/*"`, Field: "open.filename", Expected: FieldValue{Value: "/proc/1/*", Type: PatternValueType}},
  1350  	}
  1351  
  1352  	for _, test := range tests {
  1353  		model := &testModel{}
  1354  
  1355  		opts := newOptsWithParams(testConstants, nil)
  1356  
  1357  		rule, err := parseRule(test.Expr, model, opts)
  1358  		if err != nil {
  1359  			t.Fatalf("error while evaluating `%s`: %s", test.Expr, err)
  1360  		}
  1361  		values := rule.GetFieldValues(test.Field)
  1362  		if len(values) != 1 {
  1363  			t.Fatalf("expected field value not found: %+v", test.Expected)
  1364  		}
  1365  		if values[0].Type != test.Expected.Type || values[0].Value != test.Expected.Value {
  1366  			t.Errorf("field values differ %+v != %+v", test.Expected, values[0])
  1367  		}
  1368  	}
  1369  }
  1370  
  1371  func TestArithmeticOperation(t *testing.T) {
  1372  	// time reliability issue
  1373  	if runtime.GOARCH == "386" && runtime.GOOS == "windows" {
  1374  		t.Skip()
  1375  	}
  1376  
  1377  	now := time.Now().UnixNano()
  1378  
  1379  	event := &testEvent{
  1380  		process: testProcess{
  1381  			name:      "ls",
  1382  			createdAt: now,
  1383  		},
  1384  		open: testOpen{
  1385  			openedAt: now + int64(time.Second*2),
  1386  		},
  1387  	}
  1388  
  1389  	tests := []struct {
  1390  		Expr     string
  1391  		Expected bool
  1392  	}{
  1393  		{Expr: `1 + 2 == 5 - 2 && process.name == "ls"`, Expected: true},
  1394  		{Expr: `1 + 2 != 3 && process.name == "ls"`, Expected: false},
  1395  		{Expr: `1 + 2 - 3 + 4  == 4 && process.name == "ls"`, Expected: true},
  1396  		{Expr: `1 - 2 + 3 - (1 - 4) - (1 - 5) == 9 &&  process.name == "ls"`, Expected: true},
  1397  		{Expr: `10s + 40s == 50s && process.name == "ls"`, Expected: true},
  1398  		{Expr: `process.created_at < 5s && process.name == "ls"`, Expected: true},
  1399  		{Expr: `open.opened_at - process.created_at + 3s <= 5s && process.name == "ls"`, Expected: true},
  1400  		{Expr: `open.opened_at - process.created_at + 3s <= 1s && process.name == "ls"`, Expected: false},
  1401  	}
  1402  
  1403  	for _, test := range tests {
  1404  		result, _, err := eval(t, event, test.Expr)
  1405  		if err != nil {
  1406  			t.Fatalf("error while evaluating `%s`: %s", test.Expr, err)
  1407  		}
  1408  
  1409  		if result != test.Expected {
  1410  			t.Errorf("expected result `%t` not found, got `%t`\n%s", test.Expected, result, test.Expr)
  1411  		}
  1412  	}
  1413  }
  1414  
  1415  func BenchmarkArray(b *testing.B) {
  1416  	event := &testEvent{
  1417  		process: testProcess{
  1418  			name: "/usr/bin/ls",
  1419  			uid:  1,
  1420  		},
  1421  	}
  1422  
  1423  	var values []string
  1424  	for i := 0; i != 255; i++ {
  1425  		values = append(values, fmt.Sprintf(`~"/usr/bin/aaa-%d"`, i))
  1426  	}
  1427  
  1428  	for i := 0; i != 255; i++ {
  1429  		values = append(values, fmt.Sprintf(`"/usr/bin/aaa-%d"`, i))
  1430  	}
  1431  
  1432  	base := fmt.Sprintf(`(process.name in [%s, ~"/usr/bin/ls"])`, strings.Join(values, ","))
  1433  	var exprs []string
  1434  
  1435  	for i := 0; i != 100; i++ {
  1436  		exprs = append(exprs, base)
  1437  	}
  1438  
  1439  	expr := strings.Join(exprs, " && ")
  1440  	opts := newOptsWithParams(nil, nil)
  1441  
  1442  	rule, err := parseRule(expr, &testModel{}, opts)
  1443  	if err != nil {
  1444  		b.Fatalf("%s\n%s", err, expr)
  1445  	}
  1446  
  1447  	evaluator := rule.GetEvaluator()
  1448  
  1449  	b.ResetTimer()
  1450  	for i := 0; i < b.N; i++ {
  1451  		ctx := NewContext(event)
  1452  		if evaluator.Eval(ctx) != true {
  1453  			b.Fatal("unexpected result")
  1454  		}
  1455  	}
  1456  }
  1457  
  1458  func BenchmarkComplex(b *testing.B) {
  1459  	event := &testEvent{
  1460  		process: testProcess{
  1461  			name: "/usr/bin/ls",
  1462  			uid:  1,
  1463  		},
  1464  	}
  1465  
  1466  	base := `(process.name == "/usr/bin/ls" && process.uid == 1)`
  1467  	var exprs []string
  1468  
  1469  	for i := 0; i != 100; i++ {
  1470  		exprs = append(exprs, base)
  1471  	}
  1472  
  1473  	expr := strings.Join(exprs, " && ")
  1474  	opts := newOptsWithParams(nil, nil)
  1475  
  1476  	rule, err := parseRule(expr, &testModel{}, opts)
  1477  	if err != nil {
  1478  		b.Fatalf("%s\n%s", err, expr)
  1479  	}
  1480  
  1481  	evaluator := rule.GetEvaluator()
  1482  
  1483  	b.ResetTimer()
  1484  	for i := 0; i < b.N; i++ {
  1485  		ctx := NewContext(event)
  1486  		if evaluator.Eval(ctx) != true {
  1487  			b.Fatal("unexpected result")
  1488  		}
  1489  	}
  1490  }
  1491  
  1492  func BenchmarkPartial(b *testing.B) {
  1493  	event := &testEvent{
  1494  		process: testProcess{
  1495  			name: "abc",
  1496  			uid:  1,
  1497  		},
  1498  	}
  1499  
  1500  	ctx := NewContext(event)
  1501  
  1502  	base := `(process.name == "/usr/bin/ls" && process.uid != 0)`
  1503  	var exprs []string
  1504  
  1505  	for i := 0; i != 100; i++ {
  1506  		exprs = append(exprs, base)
  1507  	}
  1508  
  1509  	expr := strings.Join(exprs, " && ")
  1510  	model := &testModel{}
  1511  	opts := newOptsWithParams(nil, nil)
  1512  
  1513  	rule, err := parseRule(expr, model, opts)
  1514  	if err != nil {
  1515  		b.Fatal(err)
  1516  	}
  1517  
  1518  	pc := ast.NewParsingContext()
  1519  	if err := rule.GenEvaluator(model, pc); err != nil {
  1520  		b.Fatal(err)
  1521  	}
  1522  
  1523  	evaluator := rule.GetEvaluator()
  1524  
  1525  	b.ResetTimer()
  1526  	for i := 0; i < b.N; i++ {
  1527  		if ok, _ := evaluator.PartialEval(ctx, "process.name"); ok {
  1528  			b.Fatal("unexpected result")
  1529  		}
  1530  	}
  1531  }
  1532  
  1533  func BenchmarkPool(b *testing.B) {
  1534  	event := &testEvent{
  1535  		process: testProcess{
  1536  			name: "/usr/bin/ls",
  1537  			uid:  1,
  1538  		},
  1539  	}
  1540  
  1541  	pool := NewContextPool()
  1542  
  1543  	base := `(process.name == "/usr/bin/ls" && process.uid == 1)`
  1544  	var exprs []string
  1545  
  1546  	for i := 0; i != 100; i++ {
  1547  		exprs = append(exprs, base)
  1548  	}
  1549  
  1550  	expr := strings.Join(exprs, " && ")
  1551  	opts := newOptsWithParams(nil, nil)
  1552  
  1553  	rule, err := parseRule(expr, &testModel{}, opts)
  1554  	if err != nil {
  1555  		b.Fatalf("%s\n%s", err, expr)
  1556  	}
  1557  
  1558  	evaluator := rule.GetEvaluator()
  1559  
  1560  	b.ResetTimer()
  1561  	for i := 0; i < b.N; i++ {
  1562  		ctx := pool.Get(event)
  1563  		if evaluator.Eval(ctx) != true {
  1564  			b.Fatal("unexpected result")
  1565  		}
  1566  		pool.pool.Put(ctx)
  1567  	}
  1568  }