github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/seccomp/seccomp_test.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package seccomp 16 17 import ( 18 "bytes" 19 "fmt" 20 "io" 21 "io/ioutil" 22 "math" 23 "math/rand" 24 "os" 25 "os/exec" 26 "strings" 27 "testing" 28 "time" 29 30 "github.com/SagerNet/gvisor/pkg/abi/linux" 31 "github.com/SagerNet/gvisor/pkg/bpf" 32 "github.com/SagerNet/gvisor/pkg/hostarch" 33 ) 34 35 // newVictim makes a victim binary. 36 func newVictim() (string, error) { 37 f, err := ioutil.TempFile("", "victim") 38 if err != nil { 39 return "", err 40 } 41 defer f.Close() 42 path := f.Name() 43 if _, err := io.Copy(f, bytes.NewBuffer(victimData)); err != nil { 44 os.Remove(path) 45 return "", err 46 } 47 if err := os.Chmod(path, 0755); err != nil { 48 os.Remove(path) 49 return "", err 50 } 51 return path, nil 52 } 53 54 // dataAsInput converts a linux.SeccompData to a bpf.Input. 55 func dataAsInput(d *linux.SeccompData) bpf.Input { 56 buf := make([]byte, d.SizeBytes()) 57 d.MarshalUnsafe(buf) 58 return bpf.InputBytes{ 59 Data: buf, 60 Order: hostarch.ByteOrder, 61 } 62 } 63 64 func TestBasic(t *testing.T) { 65 type spec struct { 66 // desc is the test's description. 67 desc string 68 69 // data is the input data. 70 data linux.SeccompData 71 72 // want is the expected return value of the BPF program. 73 want linux.BPFAction 74 } 75 76 for _, test := range []struct { 77 name string 78 ruleSets []RuleSet 79 defaultAction linux.BPFAction 80 badArchAction linux.BPFAction 81 specs []spec 82 }{ 83 { 84 name: "Single syscall", 85 ruleSets: []RuleSet{ 86 { 87 Rules: SyscallRules{1: {}}, 88 Action: linux.SECCOMP_RET_ALLOW, 89 }, 90 }, 91 defaultAction: linux.SECCOMP_RET_TRAP, 92 badArchAction: linux.SECCOMP_RET_KILL_THREAD, 93 specs: []spec{ 94 { 95 desc: "syscall allowed", 96 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH}, 97 want: linux.SECCOMP_RET_ALLOW, 98 }, 99 { 100 desc: "syscall disallowed", 101 data: linux.SeccompData{Nr: 2, Arch: LINUX_AUDIT_ARCH}, 102 want: linux.SECCOMP_RET_TRAP, 103 }, 104 }, 105 }, 106 { 107 name: "Multiple rulesets", 108 ruleSets: []RuleSet{ 109 { 110 Rules: SyscallRules{ 111 1: []Rule{ 112 { 113 EqualTo(0x1), 114 }, 115 }, 116 }, 117 Action: linux.SECCOMP_RET_ALLOW, 118 }, 119 { 120 Rules: SyscallRules{ 121 1: {}, 122 2: {}, 123 }, 124 Action: linux.SECCOMP_RET_TRAP, 125 }, 126 }, 127 defaultAction: linux.SECCOMP_RET_KILL_THREAD, 128 badArchAction: linux.SECCOMP_RET_KILL_THREAD, 129 specs: []spec{ 130 { 131 desc: "allowed (1a)", 132 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x1}}, 133 want: linux.SECCOMP_RET_ALLOW, 134 }, 135 { 136 desc: "allowed (1b)", 137 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH}, 138 want: linux.SECCOMP_RET_TRAP, 139 }, 140 { 141 desc: "syscall 1 matched 2nd rule", 142 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH}, 143 want: linux.SECCOMP_RET_TRAP, 144 }, 145 { 146 desc: "no match", 147 data: linux.SeccompData{Nr: 0, Arch: LINUX_AUDIT_ARCH}, 148 want: linux.SECCOMP_RET_KILL_THREAD, 149 }, 150 }, 151 }, 152 { 153 name: "Multiple syscalls", 154 ruleSets: []RuleSet{ 155 { 156 Rules: SyscallRules{ 157 1: {}, 158 3: {}, 159 5: {}, 160 }, 161 Action: linux.SECCOMP_RET_ALLOW, 162 }, 163 }, 164 defaultAction: linux.SECCOMP_RET_TRAP, 165 badArchAction: linux.SECCOMP_RET_KILL_THREAD, 166 specs: []spec{ 167 { 168 desc: "allowed (1)", 169 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH}, 170 want: linux.SECCOMP_RET_ALLOW, 171 }, 172 { 173 desc: "allowed (3)", 174 data: linux.SeccompData{Nr: 3, Arch: LINUX_AUDIT_ARCH}, 175 want: linux.SECCOMP_RET_ALLOW, 176 }, 177 { 178 desc: "allowed (5)", 179 data: linux.SeccompData{Nr: 5, Arch: LINUX_AUDIT_ARCH}, 180 want: linux.SECCOMP_RET_ALLOW, 181 }, 182 { 183 desc: "disallowed (0)", 184 data: linux.SeccompData{Nr: 0, Arch: LINUX_AUDIT_ARCH}, 185 want: linux.SECCOMP_RET_TRAP, 186 }, 187 { 188 desc: "disallowed (2)", 189 data: linux.SeccompData{Nr: 2, Arch: LINUX_AUDIT_ARCH}, 190 want: linux.SECCOMP_RET_TRAP, 191 }, 192 { 193 desc: "disallowed (4)", 194 data: linux.SeccompData{Nr: 4, Arch: LINUX_AUDIT_ARCH}, 195 want: linux.SECCOMP_RET_TRAP, 196 }, 197 { 198 desc: "disallowed (6)", 199 data: linux.SeccompData{Nr: 6, Arch: LINUX_AUDIT_ARCH}, 200 want: linux.SECCOMP_RET_TRAP, 201 }, 202 { 203 desc: "disallowed (100)", 204 data: linux.SeccompData{Nr: 100, Arch: LINUX_AUDIT_ARCH}, 205 want: linux.SECCOMP_RET_TRAP, 206 }, 207 }, 208 }, 209 { 210 name: "Wrong architecture", 211 ruleSets: []RuleSet{ 212 { 213 Rules: SyscallRules{ 214 1: {}, 215 }, 216 Action: linux.SECCOMP_RET_ALLOW, 217 }, 218 }, 219 defaultAction: linux.SECCOMP_RET_TRAP, 220 badArchAction: linux.SECCOMP_RET_KILL_THREAD, 221 specs: []spec{ 222 { 223 desc: "arch (123)", 224 data: linux.SeccompData{Nr: 1, Arch: 123}, 225 want: linux.SECCOMP_RET_KILL_THREAD, 226 }, 227 }, 228 }, 229 { 230 name: "Syscall disallowed", 231 ruleSets: []RuleSet{ 232 { 233 Rules: SyscallRules{ 234 1: {}, 235 }, 236 Action: linux.SECCOMP_RET_ALLOW, 237 }, 238 }, 239 defaultAction: linux.SECCOMP_RET_TRAP, 240 badArchAction: linux.SECCOMP_RET_KILL_THREAD, 241 specs: []spec{ 242 { 243 desc: "action trap", 244 data: linux.SeccompData{Nr: 2, Arch: LINUX_AUDIT_ARCH}, 245 want: linux.SECCOMP_RET_TRAP, 246 }, 247 }, 248 }, 249 { 250 name: "Syscall arguments", 251 ruleSets: []RuleSet{ 252 { 253 Rules: SyscallRules{ 254 1: []Rule{ 255 { 256 MatchAny{}, 257 EqualTo(0xf), 258 }, 259 }, 260 }, 261 Action: linux.SECCOMP_RET_ALLOW, 262 }, 263 }, 264 defaultAction: linux.SECCOMP_RET_TRAP, 265 badArchAction: linux.SECCOMP_RET_KILL_THREAD, 266 specs: []spec{ 267 { 268 desc: "allowed", 269 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0xf, 0xf}}, 270 want: linux.SECCOMP_RET_ALLOW, 271 }, 272 { 273 desc: "disallowed", 274 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0xf, 0xe}}, 275 want: linux.SECCOMP_RET_TRAP, 276 }, 277 }, 278 }, 279 { 280 name: "Multiple arguments", 281 ruleSets: []RuleSet{ 282 { 283 Rules: SyscallRules{ 284 1: []Rule{ 285 { 286 EqualTo(0xf), 287 }, 288 { 289 EqualTo(0xe), 290 }, 291 }, 292 }, 293 Action: linux.SECCOMP_RET_ALLOW, 294 }, 295 }, 296 defaultAction: linux.SECCOMP_RET_TRAP, 297 badArchAction: linux.SECCOMP_RET_KILL_THREAD, 298 specs: []spec{ 299 { 300 desc: "match first rule", 301 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0xf}}, 302 want: linux.SECCOMP_RET_ALLOW, 303 }, 304 { 305 desc: "match 2nd rule", 306 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0xe}}, 307 want: linux.SECCOMP_RET_ALLOW, 308 }, 309 }, 310 }, 311 { 312 name: "EqualTo", 313 ruleSets: []RuleSet{ 314 { 315 Rules: SyscallRules{ 316 1: []Rule{ 317 { 318 EqualTo(0), 319 EqualTo(math.MaxUint64 - 1), 320 EqualTo(math.MaxUint32), 321 }, 322 }, 323 }, 324 Action: linux.SECCOMP_RET_ALLOW, 325 }, 326 }, 327 defaultAction: linux.SECCOMP_RET_TRAP, 328 badArchAction: linux.SECCOMP_RET_KILL_THREAD, 329 specs: []spec{ 330 { 331 desc: "argument allowed (all match)", 332 data: linux.SeccompData{ 333 Nr: 1, 334 Arch: LINUX_AUDIT_ARCH, 335 Args: [6]uint64{0, math.MaxUint64 - 1, math.MaxUint32}, 336 }, 337 want: linux.SECCOMP_RET_ALLOW, 338 }, 339 { 340 desc: "argument disallowed (one mismatch)", 341 data: linux.SeccompData{ 342 Nr: 1, 343 Arch: LINUX_AUDIT_ARCH, 344 Args: [6]uint64{0, math.MaxUint64, math.MaxUint32}, 345 }, 346 want: linux.SECCOMP_RET_TRAP, 347 }, 348 { 349 desc: "argument disallowed (multiple mismatch)", 350 data: linux.SeccompData{ 351 Nr: 1, 352 Arch: LINUX_AUDIT_ARCH, 353 Args: [6]uint64{0, math.MaxUint64, math.MaxUint32 - 1}, 354 }, 355 want: linux.SECCOMP_RET_TRAP, 356 }, 357 }, 358 }, 359 { 360 name: "NotEqual", 361 ruleSets: []RuleSet{ 362 { 363 Rules: SyscallRules{ 364 1: []Rule{ 365 { 366 NotEqual(0x7aabbccdd), 367 NotEqual(math.MaxUint64 - 1), 368 NotEqual(math.MaxUint32), 369 }, 370 }, 371 }, 372 Action: linux.SECCOMP_RET_ALLOW, 373 }, 374 }, 375 defaultAction: linux.SECCOMP_RET_TRAP, 376 badArchAction: linux.SECCOMP_RET_KILL_THREAD, 377 specs: []spec{ 378 { 379 desc: "arg allowed", 380 data: linux.SeccompData{ 381 Nr: 1, 382 Arch: LINUX_AUDIT_ARCH, 383 Args: [6]uint64{0, math.MaxUint64, math.MaxUint32 - 1}, 384 }, 385 want: linux.SECCOMP_RET_ALLOW, 386 }, 387 { 388 desc: "arg disallowed (one equal)", 389 data: linux.SeccompData{ 390 Nr: 1, 391 Arch: LINUX_AUDIT_ARCH, 392 Args: [6]uint64{0x7aabbccdd, math.MaxUint64, math.MaxUint32 - 1}, 393 }, 394 want: linux.SECCOMP_RET_TRAP, 395 }, 396 { 397 desc: "arg disallowed (all equal)", 398 data: linux.SeccompData{ 399 Nr: 1, 400 Arch: LINUX_AUDIT_ARCH, 401 Args: [6]uint64{0x7aabbccdd, math.MaxUint64 - 1, math.MaxUint32}, 402 }, 403 want: linux.SECCOMP_RET_TRAP, 404 }, 405 }, 406 }, 407 { 408 name: "GreaterThan", 409 ruleSets: []RuleSet{ 410 { 411 Rules: SyscallRules{ 412 1: []Rule{ 413 { 414 // 4294967298 415 // Both upper 32 bits and lower 32 bits are non-zero. 416 // 00000000000000000000000000000010 417 // 00000000000000000000000000000010 418 GreaterThan(0x00000002_00000002), 419 }, 420 }, 421 }, 422 Action: linux.SECCOMP_RET_ALLOW, 423 }, 424 }, 425 defaultAction: linux.SECCOMP_RET_TRAP, 426 badArchAction: linux.SECCOMP_RET_KILL_THREAD, 427 specs: []spec{ 428 { 429 desc: "high 32bits greater", 430 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000003_00000002}}, 431 want: linux.SECCOMP_RET_ALLOW, 432 }, 433 { 434 desc: "high 32bits equal, low 32bits greater", 435 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000003}}, 436 want: linux.SECCOMP_RET_ALLOW, 437 }, 438 { 439 desc: "high 32bits equal, low 32bits equal", 440 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000002}}, 441 want: linux.SECCOMP_RET_TRAP, 442 }, 443 { 444 desc: "high 32bits equal, low 32bits less", 445 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000001}}, 446 want: linux.SECCOMP_RET_TRAP, 447 }, 448 { 449 desc: "high 32bits less", 450 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000001_00000003}}, 451 want: linux.SECCOMP_RET_TRAP, 452 }, 453 }, 454 }, 455 { 456 name: "GreaterThan (multi)", 457 ruleSets: []RuleSet{ 458 { 459 Rules: SyscallRules{ 460 1: []Rule{ 461 { 462 GreaterThan(0xf), 463 GreaterThan(0xabcd000d), 464 }, 465 }, 466 }, 467 Action: linux.SECCOMP_RET_ALLOW, 468 }, 469 }, 470 defaultAction: linux.SECCOMP_RET_TRAP, 471 badArchAction: linux.SECCOMP_RET_KILL_THREAD, 472 specs: []spec{ 473 { 474 desc: "arg allowed", 475 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x10, 0xffffffff}}, 476 want: linux.SECCOMP_RET_ALLOW, 477 }, 478 { 479 desc: "arg disallowed (first arg equal)", 480 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0xf, 0xffffffff}}, 481 want: linux.SECCOMP_RET_TRAP, 482 }, 483 { 484 desc: "arg disallowed (first arg smaller)", 485 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x0, 0xffffffff}}, 486 want: linux.SECCOMP_RET_TRAP, 487 }, 488 { 489 desc: "arg disallowed (second arg equal)", 490 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x10, 0xabcd000d}}, 491 want: linux.SECCOMP_RET_TRAP, 492 }, 493 { 494 desc: "arg disallowed (second arg smaller)", 495 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x10, 0xa000ffff}}, 496 want: linux.SECCOMP_RET_TRAP, 497 }, 498 }, 499 }, 500 { 501 name: "GreaterThanOrEqual", 502 ruleSets: []RuleSet{ 503 { 504 Rules: SyscallRules{ 505 1: []Rule{ 506 { 507 // 4294967298 508 // Both upper 32 bits and lower 32 bits are non-zero. 509 // 00000000000000000000000000000010 510 // 00000000000000000000000000000010 511 GreaterThanOrEqual(0x00000002_00000002), 512 }, 513 }, 514 }, 515 Action: linux.SECCOMP_RET_ALLOW, 516 }, 517 }, 518 defaultAction: linux.SECCOMP_RET_TRAP, 519 badArchAction: linux.SECCOMP_RET_KILL_THREAD, 520 specs: []spec{ 521 { 522 desc: "high 32bits greater", 523 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000003_00000002}}, 524 want: linux.SECCOMP_RET_ALLOW, 525 }, 526 { 527 desc: "high 32bits equal, low 32bits greater", 528 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000003}}, 529 want: linux.SECCOMP_RET_ALLOW, 530 }, 531 { 532 desc: "high 32bits equal, low 32bits equal", 533 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000002}}, 534 want: linux.SECCOMP_RET_ALLOW, 535 }, 536 { 537 desc: "high 32bits equal, low 32bits less", 538 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000001}}, 539 want: linux.SECCOMP_RET_TRAP, 540 }, 541 { 542 desc: "high 32bits less", 543 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000001_00000002}}, 544 want: linux.SECCOMP_RET_TRAP, 545 }, 546 }, 547 }, 548 { 549 name: "GreaterThanOrEqual (multi)", 550 ruleSets: []RuleSet{ 551 { 552 Rules: SyscallRules{ 553 1: []Rule{ 554 { 555 GreaterThanOrEqual(0xf), 556 GreaterThanOrEqual(0xabcd000d), 557 }, 558 }, 559 }, 560 Action: linux.SECCOMP_RET_ALLOW, 561 }, 562 }, 563 defaultAction: linux.SECCOMP_RET_TRAP, 564 badArchAction: linux.SECCOMP_RET_KILL_THREAD, 565 specs: []spec{ 566 { 567 desc: "arg allowed (both greater)", 568 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x10, 0xffffffff}}, 569 want: linux.SECCOMP_RET_ALLOW, 570 }, 571 { 572 desc: "arg allowed (first arg equal)", 573 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0xf, 0xffffffff}}, 574 want: linux.SECCOMP_RET_ALLOW, 575 }, 576 { 577 desc: "arg disallowed (first arg smaller)", 578 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x0, 0xffffffff}}, 579 want: linux.SECCOMP_RET_TRAP, 580 }, 581 { 582 desc: "arg allowed (second arg equal)", 583 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x10, 0xabcd000d}}, 584 want: linux.SECCOMP_RET_ALLOW, 585 }, 586 { 587 desc: "arg disallowed (second arg smaller)", 588 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x10, 0xa000ffff}}, 589 want: linux.SECCOMP_RET_TRAP, 590 }, 591 { 592 desc: "arg disallowed (both arg smaller)", 593 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x0, 0xa000ffff}}, 594 want: linux.SECCOMP_RET_TRAP, 595 }, 596 }, 597 }, 598 { 599 name: "LessThan", 600 ruleSets: []RuleSet{ 601 { 602 Rules: SyscallRules{ 603 1: []Rule{ 604 { 605 // 4294967298 606 // Both upper 32 bits and lower 32 bits are non-zero. 607 // 00000000000000000000000000000010 608 // 00000000000000000000000000000010 609 LessThan(0x00000002_00000002), 610 }, 611 }, 612 }, 613 Action: linux.SECCOMP_RET_ALLOW, 614 }, 615 }, 616 defaultAction: linux.SECCOMP_RET_TRAP, 617 badArchAction: linux.SECCOMP_RET_KILL_THREAD, 618 specs: []spec{ 619 { 620 desc: "high 32bits greater", 621 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000003_00000002}}, 622 want: linux.SECCOMP_RET_TRAP, 623 }, 624 { 625 desc: "high 32bits equal, low 32bits greater", 626 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000003}}, 627 want: linux.SECCOMP_RET_TRAP, 628 }, 629 { 630 desc: "high 32bits equal, low 32bits equal", 631 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000002}}, 632 want: linux.SECCOMP_RET_TRAP, 633 }, 634 { 635 desc: "high 32bits equal, low 32bits less", 636 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000001}}, 637 want: linux.SECCOMP_RET_ALLOW, 638 }, 639 { 640 desc: "high 32bits less", 641 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000001_00000002}}, 642 want: linux.SECCOMP_RET_ALLOW, 643 }, 644 }, 645 }, 646 { 647 name: "LessThan (multi)", 648 ruleSets: []RuleSet{ 649 { 650 Rules: SyscallRules{ 651 1: []Rule{ 652 { 653 LessThan(0x1), 654 LessThan(0xabcd000d), 655 }, 656 }, 657 }, 658 Action: linux.SECCOMP_RET_ALLOW, 659 }, 660 }, 661 defaultAction: linux.SECCOMP_RET_TRAP, 662 badArchAction: linux.SECCOMP_RET_KILL_THREAD, 663 specs: []spec{ 664 { 665 desc: "arg allowed", 666 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x0, 0x0}}, 667 want: linux.SECCOMP_RET_ALLOW, 668 }, 669 { 670 desc: "arg disallowed (first arg equal)", 671 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x1, 0x0}}, 672 want: linux.SECCOMP_RET_TRAP, 673 }, 674 { 675 desc: "arg disallowed (first arg greater)", 676 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x2, 0x0}}, 677 want: linux.SECCOMP_RET_TRAP, 678 }, 679 { 680 desc: "arg disallowed (second arg equal)", 681 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x0, 0xabcd000d}}, 682 want: linux.SECCOMP_RET_TRAP, 683 }, 684 { 685 desc: "arg disallowed (second arg greater)", 686 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x0, 0xffffffff}}, 687 want: linux.SECCOMP_RET_TRAP, 688 }, 689 { 690 desc: "arg disallowed (both arg greater)", 691 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x2, 0xffffffff}}, 692 want: linux.SECCOMP_RET_TRAP, 693 }, 694 }, 695 }, 696 { 697 name: "LessThanOrEqual", 698 ruleSets: []RuleSet{ 699 { 700 Rules: SyscallRules{ 701 1: []Rule{ 702 { 703 // 4294967298 704 // Both upper 32 bits and lower 32 bits are non-zero. 705 // 00000000000000000000000000000010 706 // 00000000000000000000000000000010 707 LessThanOrEqual(0x00000002_00000002), 708 }, 709 }, 710 }, 711 Action: linux.SECCOMP_RET_ALLOW, 712 }, 713 }, 714 defaultAction: linux.SECCOMP_RET_TRAP, 715 badArchAction: linux.SECCOMP_RET_KILL_THREAD, 716 specs: []spec{ 717 { 718 desc: "high 32bits greater", 719 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000003_00000002}}, 720 want: linux.SECCOMP_RET_TRAP, 721 }, 722 { 723 desc: "high 32bits equal, low 32bits greater", 724 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000003}}, 725 want: linux.SECCOMP_RET_TRAP, 726 }, 727 { 728 desc: "high 32bits equal, low 32bits equal", 729 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000002}}, 730 want: linux.SECCOMP_RET_ALLOW, 731 }, 732 { 733 desc: "high 32bits equal, low 32bits less", 734 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000002_00000001}}, 735 want: linux.SECCOMP_RET_ALLOW, 736 }, 737 { 738 desc: "high 32bits less", 739 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x00000001_00000002}}, 740 want: linux.SECCOMP_RET_ALLOW, 741 }, 742 }, 743 }, 744 745 { 746 name: "LessThanOrEqual (multi)", 747 ruleSets: []RuleSet{ 748 { 749 Rules: SyscallRules{ 750 1: []Rule{ 751 { 752 LessThanOrEqual(0x1), 753 LessThanOrEqual(0xabcd000d), 754 }, 755 }, 756 }, 757 Action: linux.SECCOMP_RET_ALLOW, 758 }, 759 }, 760 defaultAction: linux.SECCOMP_RET_TRAP, 761 badArchAction: linux.SECCOMP_RET_KILL_THREAD, 762 specs: []spec{ 763 { 764 desc: "arg allowed", 765 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x0, 0x0}}, 766 want: linux.SECCOMP_RET_ALLOW, 767 }, 768 { 769 desc: "arg allowed (first arg equal)", 770 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x1, 0x0}}, 771 want: linux.SECCOMP_RET_ALLOW, 772 }, 773 { 774 desc: "arg disallowed (first arg greater)", 775 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x2, 0x0}}, 776 want: linux.SECCOMP_RET_TRAP, 777 }, 778 { 779 desc: "arg allowed (second arg equal)", 780 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x0, 0xabcd000d}}, 781 want: linux.SECCOMP_RET_ALLOW, 782 }, 783 { 784 desc: "arg disallowed (second arg greater)", 785 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x0, 0xffffffff}}, 786 want: linux.SECCOMP_RET_TRAP, 787 }, 788 { 789 desc: "arg disallowed (both arg greater)", 790 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0x2, 0xffffffff}}, 791 want: linux.SECCOMP_RET_TRAP, 792 }, 793 }, 794 }, 795 { 796 name: "MaskedEqual", 797 ruleSets: []RuleSet{ 798 { 799 Rules: SyscallRules{ 800 1: []Rule{ 801 { 802 // x & 00000001 00000011 (0x103) == 00000000 00000001 (0x1) 803 // Input x must have lowest order bit set and 804 // must *not* have 8th or second lowest order bit set. 805 MaskedEqual(0x103, 0x1), 806 }, 807 }, 808 }, 809 Action: linux.SECCOMP_RET_ALLOW, 810 }, 811 }, 812 defaultAction: linux.SECCOMP_RET_TRAP, 813 badArchAction: linux.SECCOMP_RET_KILL_THREAD, 814 specs: []spec{ 815 { 816 desc: "arg allowed (low order mandatory bit)", 817 data: linux.SeccompData{ 818 Nr: 1, 819 Arch: LINUX_AUDIT_ARCH, 820 // 00000000 00000000 00000000 00000001 821 Args: [6]uint64{0x1}, 822 }, 823 want: linux.SECCOMP_RET_ALLOW, 824 }, 825 { 826 desc: "arg allowed (low order optional bit)", 827 data: linux.SeccompData{ 828 Nr: 1, 829 Arch: LINUX_AUDIT_ARCH, 830 // 00000000 00000000 00000000 00000101 831 Args: [6]uint64{0x5}, 832 }, 833 want: linux.SECCOMP_RET_ALLOW, 834 }, 835 { 836 desc: "arg disallowed (lowest order bit not set)", 837 data: linux.SeccompData{ 838 Nr: 1, 839 Arch: LINUX_AUDIT_ARCH, 840 // 00000000 00000000 00000000 00000010 841 Args: [6]uint64{0x2}, 842 }, 843 want: linux.SECCOMP_RET_TRAP, 844 }, 845 { 846 desc: "arg disallowed (second lowest order bit set)", 847 data: linux.SeccompData{ 848 Nr: 1, 849 Arch: LINUX_AUDIT_ARCH, 850 // 00000000 00000000 00000000 00000011 851 Args: [6]uint64{0x3}, 852 }, 853 want: linux.SECCOMP_RET_TRAP, 854 }, 855 { 856 desc: "arg disallowed (8th bit set)", 857 data: linux.SeccompData{ 858 Nr: 1, 859 Arch: LINUX_AUDIT_ARCH, 860 // 00000000 00000000 00000001 00000000 861 Args: [6]uint64{0x100}, 862 }, 863 want: linux.SECCOMP_RET_TRAP, 864 }, 865 }, 866 }, 867 { 868 name: "Instruction Pointer", 869 ruleSets: []RuleSet{ 870 { 871 Rules: SyscallRules{ 872 1: []Rule{ 873 { 874 RuleIP: EqualTo(0x7aabbccdd), 875 }, 876 }, 877 }, 878 Action: linux.SECCOMP_RET_ALLOW, 879 }, 880 }, 881 defaultAction: linux.SECCOMP_RET_TRAP, 882 badArchAction: linux.SECCOMP_RET_KILL_THREAD, 883 specs: []spec{ 884 { 885 desc: "allowed", 886 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{}, InstructionPointer: 0x7aabbccdd}, 887 want: linux.SECCOMP_RET_ALLOW, 888 }, 889 { 890 desc: "disallowed", 891 data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{}, InstructionPointer: 0x711223344}, 892 want: linux.SECCOMP_RET_TRAP, 893 }, 894 }, 895 }, 896 } { 897 t.Run(test.name, func(t *testing.T) { 898 instrs, err := BuildProgram(test.ruleSets, test.defaultAction, test.badArchAction) 899 if err != nil { 900 t.Fatalf("BuildProgram() got error: %v", err) 901 } 902 p, err := bpf.Compile(instrs) 903 if err != nil { 904 t.Fatalf("bpf.Compile() got error: %v", err) 905 } 906 for _, spec := range test.specs { 907 got, err := bpf.Exec(p, dataAsInput(&spec.data)) 908 if err != nil { 909 t.Fatalf("%s: bpf.Exec() got error: %v", spec.desc, err) 910 } 911 if got != uint32(spec.want) { 912 // Include a decoded version of the program in output for debugging purposes. 913 decoded, _ := bpf.DecodeInstructions(instrs) 914 t.Fatalf("%s: got: %d, want: %d\nBPF Program\n%s", spec.desc, got, spec.want, decoded) 915 } 916 } 917 }) 918 } 919 } 920 921 // TestRandom tests that randomly generated rules are encoded correctly. 922 func TestRandom(t *testing.T) { 923 rand.Seed(time.Now().UnixNano()) 924 size := rand.Intn(50) + 1 925 syscallRules := make(map[uintptr][]Rule) 926 for len(syscallRules) < size { 927 n := uintptr(rand.Intn(200)) 928 if _, ok := syscallRules[n]; !ok { 929 syscallRules[n] = []Rule{} 930 } 931 } 932 933 t.Logf("Testing filters: %v", syscallRules) 934 instrs, err := BuildProgram([]RuleSet{ 935 { 936 Rules: syscallRules, 937 Action: linux.SECCOMP_RET_ALLOW, 938 }, 939 }, linux.SECCOMP_RET_TRAP, linux.SECCOMP_RET_KILL_THREAD) 940 if err != nil { 941 t.Fatalf("buildProgram() got error: %v", err) 942 } 943 p, err := bpf.Compile(instrs) 944 if err != nil { 945 t.Fatalf("bpf.Compile() got error: %v", err) 946 } 947 for i := uint32(0); i < 200; i++ { 948 data := linux.SeccompData{Nr: int32(i), Arch: LINUX_AUDIT_ARCH} 949 got, err := bpf.Exec(p, dataAsInput(&data)) 950 if err != nil { 951 t.Errorf("bpf.Exec() got error: %v, for syscall %d", err, i) 952 continue 953 } 954 want := linux.SECCOMP_RET_TRAP 955 if _, ok := syscallRules[uintptr(i)]; ok { 956 want = linux.SECCOMP_RET_ALLOW 957 } 958 if got != uint32(want) { 959 t.Errorf("bpf.Exec() = %d, want: %d, for syscall %d", got, want, i) 960 } 961 } 962 } 963 964 // TestReadDeal checks that a process dies when it trips over the filter and 965 // that it doesn't die when the filter is not triggered. 966 func TestRealDeal(t *testing.T) { 967 for _, test := range []struct { 968 die bool 969 want string 970 }{ 971 {die: true, want: "bad system call"}, 972 {die: false, want: "Syscall was allowed!!!"}, 973 } { 974 victim, err := newVictim() 975 if err != nil { 976 t.Fatalf("unable to get victim: %v", err) 977 } 978 defer os.Remove(victim) 979 dieFlag := fmt.Sprintf("-die=%v", test.die) 980 cmd := exec.Command(victim, dieFlag) 981 982 out, err := cmd.CombinedOutput() 983 if test.die { 984 if err == nil { 985 t.Errorf("victim was not killed as expected, output: %s", out) 986 continue 987 } 988 // Depending on kernel version, either RET_TRAP or RET_KILL_PROCESS is 989 // used. RET_TRAP dumps reason for exit in output, while RET_KILL_PROCESS 990 // returns SIGSYS as exit status. 991 if !strings.Contains(string(out), test.want) && 992 !strings.Contains(err.Error(), test.want) { 993 t.Errorf("Victim error is wrong, got: %v, err: %v, want: %v", string(out), err, test.want) 994 continue 995 } 996 } else { 997 if err != nil { 998 t.Errorf("victim failed to execute, err: %v", err) 999 continue 1000 } 1001 if !strings.Contains(string(out), test.want) { 1002 t.Errorf("Victim output is wrong, got: %v, want: %v", string(out), test.want) 1003 continue 1004 } 1005 } 1006 } 1007 } 1008 1009 // TestMerge ensures that empty rules are not erased when rules are merged. 1010 func TestMerge(t *testing.T) { 1011 for _, tst := range []struct { 1012 name string 1013 main []Rule 1014 merge []Rule 1015 want []Rule 1016 }{ 1017 { 1018 name: "empty both", 1019 main: nil, 1020 merge: nil, 1021 want: []Rule{{}, {}}, 1022 }, 1023 { 1024 name: "empty main", 1025 main: nil, 1026 merge: []Rule{{}}, 1027 want: []Rule{{}, {}}, 1028 }, 1029 { 1030 name: "empty merge", 1031 main: []Rule{{}}, 1032 merge: nil, 1033 want: []Rule{{}, {}}, 1034 }, 1035 } { 1036 t.Run(tst.name, func(t *testing.T) { 1037 mainRules := SyscallRules{1: tst.main} 1038 mergeRules := SyscallRules{1: tst.merge} 1039 mainRules.Merge(mergeRules) 1040 if got, want := len(mainRules[1]), len(tst.want); got != want { 1041 t.Errorf("wrong length, got: %d, want: %d", got, want) 1042 } 1043 for i, r := range mainRules[1] { 1044 if r != tst.want[i] { 1045 t.Errorf("result, got: %v, want: %v", r, tst.want[i]) 1046 } 1047 } 1048 }) 1049 } 1050 } 1051 1052 // TestAddRule ensures that empty rules are not erased when rules are added. 1053 func TestAddRule(t *testing.T) { 1054 rules := SyscallRules{1: {}} 1055 rules.AddRule(1, Rule{}) 1056 if got, want := len(rules[1]), 2; got != want { 1057 t.Errorf("len(rules[1]), got: %d, want: %d", got, want) 1058 } 1059 }