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  }