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  }