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 }