github.com/sdibtacm/sandbox@v0.0.0-20200320120712-60470cf803dc/units/seccomp/seccomp_test.go (about) 1 // +build linux 2 3 // Tests for public API of libseccomp Go bindings 4 5 package seccomp 6 7 import ( 8 "fmt" 9 "syscall" 10 "testing" 11 ) 12 13 // Type Function Tests 14 15 type versionErrorTest struct { 16 err VersionError 17 str string 18 } 19 20 var versionStr = fmt.Sprintf("%d.%d.%d", verMajor, verMinor, verMicro) 21 22 var versionErrorTests = []versionErrorTest{ 23 { 24 VersionError{ 25 "deadbeef", 26 "x.y.z", 27 }, 28 "Libseccomp version too low: deadbeef: " + 29 "minimum supported is x.y.z: detected " + versionStr, 30 }, 31 { 32 VersionError{ 33 "", 34 "x.y.z", 35 }, 36 "Libseccomp version too low: minimum supported is x.y.z: " + 37 "detected " + versionStr, 38 }, 39 { 40 VersionError{ 41 "deadbeef", 42 "", 43 }, 44 "Libseccomp version too low: " + 45 "deadbeef: minimum supported is 2.2.0: " + 46 "detected " + versionStr, 47 }, 48 { 49 VersionError{ 50 "", 51 "", 52 }, 53 "Libseccomp version too low: minimum supported is 2.2.0: " + 54 "detected " + versionStr, 55 }, 56 } 57 58 func TestVersionError(t *testing.T) { 59 for i, test := range versionErrorTests { 60 str := test.err.Error() 61 if str != test.str { 62 t.Errorf("VersionError %d: got %q: expected %q", i, str, test.str) 63 } 64 } 65 } 66 67 func ApiLevelIsSupported() bool { 68 return verMajor > 2 || 69 (verMajor == 2 && verMinor > 3) || 70 (verMajor == 2 && verMinor == 3 && verMicro >= 3) 71 } 72 73 func TestGetApiLevel(t *testing.T) { 74 api, err := GetApi() 75 if !ApiLevelIsSupported() { 76 if api != 0 { 77 t.Errorf("API level returned despite lack of support: %v", api) 78 } else if err == nil { 79 t.Errorf("No error returned despite lack of API level support") 80 } 81 82 t.Skipf("Skipping test: %s", err) 83 } else if err != nil { 84 t.Errorf("Error getting API level: %s", err) 85 } 86 fmt.Printf("Got API level of %v\n", api) 87 } 88 89 func TestSetApiLevel(t *testing.T) { 90 var expectedApi uint 91 92 expectedApi = 1 93 err := SetApi(expectedApi) 94 if !ApiLevelIsSupported() { 95 if err == nil { 96 t.Errorf("No error returned despite lack of API level support") 97 } 98 99 t.Skipf("Skipping test: %s", err) 100 } else if err != nil { 101 t.Errorf("Error setting API level: %s", err) 102 } 103 104 api, err := GetApi() 105 if err != nil { 106 t.Errorf("Error getting API level: %s", err) 107 } else if api != expectedApi { 108 t.Errorf("Got API level %v: expected %v", api, expectedApi) 109 } 110 } 111 112 func TestActionSetReturnCode(t *testing.T) { 113 if ActInvalid.SetReturnCode(0x0010) != ActInvalid { 114 t.Errorf("Able to set a return code on invalid action!") 115 } 116 117 codeSet := ActErrno.SetReturnCode(0x0001) 118 if codeSet == ActErrno || codeSet.GetReturnCode() != 0x0001 { 119 t.Errorf("Could not set return code on ActErrno") 120 } 121 } 122 123 func TestSyscallGetName(t *testing.T) { 124 call1 := ScmpSyscall(0x1) 125 callFail := ScmpSyscall(0x999) 126 127 name, err := call1.GetName() 128 if err != nil { 129 t.Errorf("Error getting syscall name for number 0x1") 130 } else if len(name) == 0 { 131 t.Errorf("Empty name returned for syscall 0x1") 132 } 133 fmt.Printf("Got name of syscall 0x1 on native arch as %s\n", name) 134 135 _, err = callFail.GetName() 136 if err == nil { 137 t.Errorf("Getting nonexistant syscall should error!") 138 } 139 } 140 141 func TestSyscallGetNameByArch(t *testing.T) { 142 call1 := ScmpSyscall(0x1) 143 callInvalid := ScmpSyscall(0x999) 144 archGood := ArchAMD64 145 archBad := ArchInvalid 146 147 name, err := call1.GetNameByArch(archGood) 148 if err != nil { 149 t.Errorf("Error getting syscall name for number 0x1 and arch AMD64") 150 } else if name != "write" { 151 t.Errorf("Got incorrect name for syscall 0x1 - expected write, got %s", name) 152 } 153 154 _, err = call1.GetNameByArch(archBad) 155 if err == nil { 156 t.Errorf("Bad architecture GetNameByArch() should error!") 157 } 158 159 _, err = callInvalid.GetNameByArch(archGood) 160 if err == nil { 161 t.Errorf("Bad syscall GetNameByArch() should error!") 162 } 163 164 _, err = callInvalid.GetNameByArch(archBad) 165 if err == nil { 166 t.Errorf("Bad syscall and bad arch GetNameByArch() should error!") 167 } 168 } 169 170 func TestGetSyscallFromName(t *testing.T) { 171 name1 := "write" 172 nameInval := "NOTASYSCALL" 173 174 syscall, err := GetSyscallFromName(name1) 175 if err != nil { 176 t.Errorf("Error getting syscall number of write: %s", err) 177 } 178 fmt.Printf("Got syscall number of write on native arch as %d\n", syscall) 179 180 _, err = GetSyscallFromName(nameInval) 181 if err == nil { 182 t.Errorf("Getting an invalid syscall should error!") 183 } 184 } 185 186 func TestGetSyscallFromNameByArch(t *testing.T) { 187 name1 := "write" 188 nameInval := "NOTASYSCALL" 189 arch1 := ArchAMD64 190 archInval := ArchInvalid 191 192 syscall, err := GetSyscallFromNameByArch(name1, arch1) 193 if err != nil { 194 t.Errorf("Error getting syscall number of write on AMD64: %s", err) 195 } 196 fmt.Printf("Got syscall number of write on AMD64 as %d\n", syscall) 197 198 _, err = GetSyscallFromNameByArch(nameInval, arch1) 199 if err == nil { 200 t.Errorf("Getting invalid syscall with valid arch should error") 201 } 202 203 _, err = GetSyscallFromNameByArch(name1, archInval) 204 if err == nil { 205 t.Errorf("Getting valid syscall for invalid arch should error") 206 } 207 208 _, err = GetSyscallFromNameByArch(nameInval, archInval) 209 if err == nil { 210 t.Errorf("Getting invalid syscall for invalid arch should error") 211 } 212 } 213 214 func TestMakeCondition(t *testing.T) { 215 condition, err := MakeCondition(3, CompareNotEqual, 0x10) 216 if err != nil { 217 t.Errorf("Error making condition struct: %s", err) 218 } else if condition.Argument != 3 || condition.Operand1 != 0x10 || 219 condition.Operand2 != 0 || condition.Op != CompareNotEqual { 220 t.Errorf("Condition struct was filled incorrectly") 221 } 222 223 condition, err = MakeCondition(3, CompareMaskedEqual, 0x10, 0x20) 224 if err != nil { 225 t.Errorf("Error making condition struct: %s", err) 226 } else if condition.Argument != 3 || condition.Operand1 != 0x10 || 227 condition.Operand2 != 0x20 || condition.Op != CompareMaskedEqual { 228 t.Errorf("Condition struct was filled incorrectly") 229 } 230 231 _, err = MakeCondition(7, CompareNotEqual, 0x10) 232 if err == nil { 233 t.Errorf("Condition struct with bad syscall argument number should error") 234 } 235 236 _, err = MakeCondition(3, CompareInvalid, 0x10) 237 if err == nil { 238 t.Errorf("Condition struct with bad comparison operator should error") 239 } 240 241 _, err = MakeCondition(3, CompareMaskedEqual, 0x10, 0x20, 0x30) 242 if err == nil { 243 t.Errorf("MakeCondition with more than 2 arguments should fail") 244 } 245 246 _, err = MakeCondition(3, CompareMaskedEqual) 247 if err == nil { 248 t.Errorf("MakeCondition with no arguments should fail") 249 } 250 } 251 252 // Utility Function Tests 253 254 func TestGetNativeArch(t *testing.T) { 255 arch, err := GetNativeArch() 256 if err != nil { 257 t.Errorf("GetNativeArch should not error!") 258 } 259 fmt.Printf("Got native arch of system as %s\n", arch.String()) 260 } 261 262 // Filter Tests 263 264 func TestFilterCreateRelease(t *testing.T) { 265 _, err := NewFilter(ActInvalid) 266 if err == nil { 267 t.Errorf("Can create filter with invalid action") 268 } 269 270 filter, err := NewFilter(ActKill) 271 if err != nil { 272 t.Errorf("Error creating filter: %s", err) 273 } 274 275 if !filter.IsValid() { 276 t.Errorf("Filter created by NewFilter was not valid") 277 } 278 279 filter.Release() 280 281 if filter.IsValid() { 282 t.Errorf("Filter is valid after being released") 283 } 284 } 285 286 func TestFilterReset(t *testing.T) { 287 filter, err := NewFilter(ActKill) 288 if err != nil { 289 t.Errorf("Error creating filter: %s", err) 290 } 291 defer filter.Release() 292 293 // Ensure the default action is ActKill 294 action, err := filter.GetDefaultAction() 295 if err != nil { 296 t.Errorf("Error getting default action of filter") 297 } else if action != ActKill { 298 t.Errorf("Default action of filter was set incorrectly!") 299 } 300 301 // Reset with a different default action 302 err = filter.Reset(ActAllow) 303 if err != nil { 304 t.Errorf("Error resetting filter!") 305 } 306 307 valid := filter.IsValid() 308 if !valid { 309 t.Errorf("Filter is no longer valid after reset!") 310 } 311 312 // The default action should no longer be ActKill 313 action, err = filter.GetDefaultAction() 314 if err != nil { 315 t.Errorf("Error getting default action of filter") 316 } else if action != ActAllow { 317 t.Errorf("Default action of filter was set incorrectly!") 318 } 319 } 320 321 func TestFilterArchFunctions(t *testing.T) { 322 filter, err := NewFilter(ActKill) 323 if err != nil { 324 t.Errorf("Error creating filter: %s", err) 325 } 326 defer filter.Release() 327 328 arch, err := GetNativeArch() 329 if err != nil { 330 t.Errorf("Error getting native architecture: %s", err) 331 } 332 333 present, err := filter.IsArchPresent(arch) 334 if err != nil { 335 t.Errorf("Error retrieving arch from filter: %s", err) 336 } else if !present { 337 t.Errorf("Filter does not contain native architecture by default") 338 } 339 340 // Adding the native arch again should succeed, as it's already present 341 err = filter.AddArch(arch) 342 if err != nil { 343 t.Errorf("Adding arch to filter already containing it should succeed") 344 } 345 346 // Make sure we don't add the native arch again 347 prospectiveArch := ArchX86 348 if arch == ArchX86 { 349 prospectiveArch = ArchAMD64 350 } 351 352 // Check to make sure this other arch isn't in the filter 353 present, err = filter.IsArchPresent(prospectiveArch) 354 if err != nil { 355 t.Errorf("Error retrieving arch from filter: %s", err) 356 } else if present { 357 t.Errorf("Arch not added to filter is present") 358 } 359 360 // Try removing the nonexistant arch - should succeed 361 err = filter.RemoveArch(prospectiveArch) 362 if err != nil { 363 t.Errorf("Error removing nonexistant arch: %s", err) 364 } 365 366 // Add an arch, see if it's in the filter 367 err = filter.AddArch(prospectiveArch) 368 if err != nil { 369 t.Errorf("Could not add arch %s to filter: %s", 370 prospectiveArch.String(), err) 371 } 372 373 present, err = filter.IsArchPresent(prospectiveArch) 374 if err != nil { 375 t.Errorf("Error retrieving arch from filter: %s", err) 376 } else if !present { 377 t.Errorf("Filter does not contain architecture %s after it was added", 378 prospectiveArch.String()) 379 } 380 381 // Remove the arch again, make sure it's not in the filter 382 err = filter.RemoveArch(prospectiveArch) 383 if err != nil { 384 t.Errorf("Could not remove arch %s from filter: %s", 385 prospectiveArch.String(), err) 386 } 387 388 present, err = filter.IsArchPresent(prospectiveArch) 389 if err != nil { 390 t.Errorf("Error retrieving arch from filter: %s", err) 391 } else if present { 392 t.Errorf("Filter contains architecture %s after it was removed", 393 prospectiveArch.String()) 394 } 395 } 396 397 func TestFilterAttributeGettersAndSetters(t *testing.T) { 398 filter, err := NewFilter(ActKill) 399 if err != nil { 400 t.Errorf("Error creating filter: %s", err) 401 } 402 defer filter.Release() 403 404 act, err := filter.GetDefaultAction() 405 if err != nil { 406 t.Errorf("Error getting default action: %s", err) 407 } else if act != ActKill { 408 t.Errorf("Default action was set incorrectly") 409 } 410 411 err = filter.SetBadArchAction(ActAllow) 412 if err != nil { 413 t.Errorf("Error setting bad arch action: %s", err) 414 } 415 416 act, err = filter.GetBadArchAction() 417 if err != nil { 418 t.Errorf("Error getting bad arch action") 419 } else if act != ActAllow { 420 t.Errorf("Bad arch action was not set correcly!") 421 } 422 423 err = filter.SetNoNewPrivsBit(false) 424 if err != nil { 425 t.Errorf("Error setting no new privileges bit") 426 } 427 428 privs, err := filter.GetNoNewPrivsBit() 429 if err != nil { 430 t.Errorf("Error getting no new privileges bit!") 431 } else if privs != false { 432 t.Errorf("No new privileges bit was not set correctly") 433 } 434 435 if ApiLevelIsSupported() { 436 api, err := GetApi() 437 if err != nil { 438 t.Errorf("Error getting API level: %s", err) 439 } else if api < 3 { 440 err = SetApi(3) 441 if err != nil { 442 t.Errorf("Error setting API level: %s", err) 443 } 444 } 445 } 446 447 err = filter.SetLogBit(true) 448 if err != nil { 449 if !ApiLevelIsSupported() { 450 t.Logf("Ignoring failure: %s\n", err) 451 } else { 452 t.Errorf("Error setting log bit") 453 } 454 } 455 456 log, err := filter.GetLogBit() 457 if err != nil { 458 if !ApiLevelIsSupported() { 459 t.Logf("Ignoring failure: %s\n", err) 460 } else { 461 t.Errorf("Error getting log bit") 462 } 463 } else if log != true { 464 t.Errorf("Log bit was not set correctly") 465 } 466 467 err = filter.SetBadArchAction(ActInvalid) 468 if err == nil { 469 t.Errorf("Setting bad arch action to an invalid action should error") 470 } 471 } 472 473 func TestMergeFilters(t *testing.T) { 474 filter1, err := NewFilter(ActAllow) 475 if err != nil { 476 t.Errorf("Error creating filter: %s", err) 477 } 478 479 filter2, err := NewFilter(ActAllow) 480 if err != nil { 481 t.Errorf("Error creating filter: %s", err) 482 } 483 484 // Need to remove the native arch and add another to the second filter 485 // Filters must NOT share architectures to be successfully merged 486 nativeArch, err := GetNativeArch() 487 if err != nil { 488 t.Errorf("Error getting native arch: %s", err) 489 } 490 491 prospectiveArch := ArchAMD64 492 if nativeArch == ArchAMD64 { 493 prospectiveArch = ArchX86 494 } 495 496 err = filter2.AddArch(prospectiveArch) 497 if err != nil { 498 t.Errorf("Error adding architecture to filter: %s", err) 499 } 500 501 err = filter2.RemoveArch(nativeArch) 502 if err != nil { 503 t.Errorf("Error removing architecture from filter: %s", err) 504 } 505 506 err = filter1.Merge(filter2) 507 if err != nil { 508 t.Errorf("Error merging filters: %s", err) 509 } 510 511 if filter2.IsValid() { 512 t.Errorf("Source filter should not be valid after merging") 513 } 514 515 filter3, err := NewFilter(ActKill) 516 if err != nil { 517 t.Errorf("Error creating filter: %s", err) 518 } 519 defer filter3.Release() 520 521 err = filter1.Merge(filter3) 522 if err == nil { 523 t.Errorf("Attributes should have to match to merge filters") 524 } 525 } 526 527 func TestRuleAddAndLoad(t *testing.T) { 528 // Test #1: Add a trivial filter 529 filter1, err := NewFilter(ActAllow) 530 if err != nil { 531 t.Errorf("Error creating filter: %s", err) 532 } 533 defer filter1.Release() 534 535 call, err := GetSyscallFromName("getpid") 536 if err != nil { 537 t.Errorf("Error getting syscall number of getpid: %s", err) 538 } 539 540 call2, err := GetSyscallFromName("setreuid") 541 if err != nil { 542 t.Errorf("Error getting syscall number of setreuid: %s", err) 543 } 544 545 call3, err := GetSyscallFromName("setreuid32") 546 if err != nil { 547 t.Errorf("Error getting syscall number of setreuid32: %s", err) 548 } 549 550 uid := syscall.Getuid() 551 euid := syscall.Geteuid() 552 553 err = filter1.AddRule(call, ActErrno.SetReturnCode(0x1)) 554 if err != nil { 555 t.Errorf("Error adding rule to restrict syscall: %s", err) 556 } 557 558 cond, err := MakeCondition(1, CompareEqual, uint64(euid)) 559 if err != nil { 560 t.Errorf("Error making rule to restrict syscall: %s", err) 561 } 562 563 cond2, err := MakeCondition(0, CompareEqual, uint64(uid)) 564 if err != nil { 565 t.Errorf("Error making rule to restrict syscall: %s", err) 566 } 567 568 conditions := []ScmpCondition{cond, cond2} 569 570 err = filter1.AddRuleConditional(call2, ActErrno.SetReturnCode(0x2), cond) 571 if err != nil { 572 t.Errorf("Error adding conditionals rule: %s", err) 573 } 574 575 err = filter1.AddRuleConditional(call2, ActErrno.SetReturnCode(0x2), cond2) 576 if err != nil { 577 t.Errorf("Error adding conditionals rule: %s", err) 578 } 579 580 err = filter1.AddRuleConditionals(call3, ActErrno.SetReturnCode(0x3), conditions) 581 if err != nil { 582 t.Errorf("Error adding second conditionals rule: %s", err) 583 } 584 585 err = filter1.Load() 586 if err != nil { 587 t.Errorf("Error loading filter: %s", err) 588 } 589 590 // Try making a simple syscall, it should error 591 pid := syscall.Getpid() 592 if pid != -1 { 593 t.Errorf("Syscall should have returned error code!") 594 } 595 596 // Try making a Geteuid syscall that should normally succeed 597 err = syscall.Setreuid(uid, euid) 598 if err == nil { 599 t.Errorf("Syscall should have returned error code!") 600 } else if err != syscall.Errno(2) && err != syscall.Errno(3) { 601 t.Errorf("Syscall returned incorrect error code - likely not blocked by Seccomp!") 602 } 603 } 604 605 func TestLogAct(t *testing.T) { 606 expectedPid := syscall.Getpid() 607 608 api, err := GetApi() 609 if err != nil { 610 if !ApiLevelIsSupported() { 611 t.Skipf("Skipping test: %s", err) 612 } 613 614 t.Errorf("Error getting API level: %s", err) 615 } else if api < 3 { 616 t.Skipf("Skipping test: API level %d is less than 3", api) 617 } 618 619 filter, err := NewFilter(ActErrno.SetReturnCode(0x0001)) 620 if err != nil { 621 t.Errorf("Error creating filter: %s", err) 622 } 623 defer filter.Release() 624 625 call, err := GetSyscallFromName("getpid") 626 if err != nil { 627 t.Errorf("Error getting syscall number of getpid: %s", err) 628 } 629 630 call1, err := GetSyscallFromName("write") 631 if err != nil { 632 t.Errorf("Error getting syscall number of write: %s", err) 633 } 634 635 call2, err := GetSyscallFromName("futex") 636 if err != nil { 637 t.Errorf("Error getting syscall number of futex: %s", err) 638 } 639 640 call3, err := GetSyscallFromName("exit_group") 641 if err != nil { 642 t.Errorf("Error getting syscall number of exit_group: %s", err) 643 } 644 645 err = filter.AddRule(call, ActLog) 646 if err != nil { 647 t.Errorf("Error adding rule to log syscall: %s", err) 648 } 649 650 err = filter.AddRule(call1, ActAllow) 651 if err != nil { 652 t.Errorf("Error adding rule to allow write syscall: %s", err) 653 } 654 655 err = filter.AddRule(call2, ActAllow) 656 if err != nil { 657 t.Errorf("Error adding rule to allow futex syscall: %s", err) 658 } 659 660 err = filter.AddRule(call3, ActAllow) 661 if err != nil { 662 t.Errorf("Error adding rule to allow exit_group syscall: %s", err) 663 } 664 665 err = filter.Load() 666 if err != nil { 667 t.Errorf("Error loading filter: %s", err) 668 } 669 670 // Try making a simple syscall, it should succeed 671 pid := syscall.Getpid() 672 if pid != expectedPid { 673 t.Errorf("Syscall should have returned expected pid (%d != %d)", pid, expectedPid) 674 } 675 }