gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/seccomp/precompiledseccomp/precompiledseccomp_test.go (about)

     1  // Copyright 2023 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 precompiledseccomp
    16  
    17  import (
    18  	"fmt"
    19  	"math"
    20  	"testing"
    21  
    22  	"golang.org/x/sys/unix"
    23  	"gvisor.dev/gvisor/pkg/abi/linux"
    24  	"gvisor.dev/gvisor/pkg/seccomp"
    25  )
    26  
    27  // TestPrecompile verifies that precompilation works and verifies that variable
    28  // offsets are verified across compilation attempts.
    29  func TestPrecompile(t *testing.T) {
    30  	// Used in some tests below that need statefulness in order to return
    31  	// purposefully-inconsistent results across calls.
    32  	counter := 0
    33  
    34  	for _, test := range []struct {
    35  		name    string
    36  		vars    []string
    37  		fn      func(Values) ProgramDesc
    38  		wantErr bool
    39  	}{
    40  		{
    41  			name: "simple case",
    42  			fn: func(Values) ProgramDesc {
    43  				return ProgramDesc{
    44  					Rules: []seccomp.RuleSet{{
    45  						Rules: seccomp.NewSyscallRules().Add(
    46  							unix.SYS_READ,
    47  							seccomp.MatchAll{},
    48  						),
    49  						Action: linux.SECCOMP_RET_ALLOW,
    50  					}},
    51  					SeccompOptions: seccomp.DefaultProgramOptions(),
    52  				}
    53  			},
    54  		},
    55  		{
    56  			name: "one variable",
    57  			vars: []string{"var1"},
    58  			fn: func(values Values) ProgramDesc {
    59  				return ProgramDesc{
    60  					Rules: []seccomp.RuleSet{{
    61  						Rules: seccomp.NewSyscallRules().Add(
    62  							unix.SYS_READ,
    63  							seccomp.PerArg{
    64  								seccomp.EqualTo(values["var1"]),
    65  							},
    66  						),
    67  						Action: linux.SECCOMP_RET_ALLOW,
    68  					}},
    69  					SeccompOptions: seccomp.DefaultProgramOptions(),
    70  				}
    71  			},
    72  		},
    73  		{
    74  			name: "duplicate variable name",
    75  			vars: []string{"var1", "var1"},
    76  			fn: func(values Values) ProgramDesc {
    77  				return ProgramDesc{}
    78  			},
    79  			wantErr: true,
    80  		},
    81  		{
    82  			name: "multiple variables showing up multiple times",
    83  			vars: []string{"var1", "var2"},
    84  			fn: func(values Values) ProgramDesc {
    85  				return ProgramDesc{
    86  					Rules: []seccomp.RuleSet{{
    87  						Rules: seccomp.NewSyscallRules().Add(
    88  							unix.SYS_READ,
    89  							seccomp.Or{
    90  								seccomp.PerArg{seccomp.EqualTo(values["var1"])},
    91  								seccomp.PerArg{seccomp.EqualTo(values["var2"])},
    92  							},
    93  						).Add(
    94  							unix.SYS_WRITE,
    95  							seccomp.PerArg{seccomp.EqualTo(values["var1"])},
    96  						),
    97  						Action: linux.SECCOMP_RET_ALLOW,
    98  					}},
    99  					SeccompOptions: seccomp.DefaultProgramOptions(),
   100  				}
   101  			},
   102  		},
   103  		{
   104  			name: "unused variable",
   105  			vars: []string{"var1"},
   106  			fn: func(values Values) ProgramDesc {
   107  				return ProgramDesc{
   108  					Rules: []seccomp.RuleSet{{
   109  						Rules: seccomp.NewSyscallRules().Add(
   110  							unix.SYS_READ,
   111  							seccomp.MatchAll{},
   112  						),
   113  						Action: linux.SECCOMP_RET_ALLOW,
   114  					}},
   115  					SeccompOptions: seccomp.DefaultProgramOptions(),
   116  				}
   117  			},
   118  			wantErr: true,
   119  		},
   120  		{
   121  			name: "variable that can be optimized away",
   122  			vars: []string{"var1"},
   123  			fn: func(values Values) ProgramDesc {
   124  				return ProgramDesc{
   125  					Rules: []seccomp.RuleSet{{
   126  						Rules: seccomp.NewSyscallRules().Add(
   127  							unix.SYS_READ,
   128  							seccomp.Or{
   129  								seccomp.PerArg{
   130  									seccomp.EqualTo(values["var1"]),
   131  								},
   132  								seccomp.MatchAll{},
   133  							},
   134  						),
   135  						Action: linux.SECCOMP_RET_ALLOW,
   136  					}},
   137  					SeccompOptions: seccomp.DefaultProgramOptions(),
   138  				}
   139  			},
   140  		},
   141  		{
   142  			name: "64-bit variable",
   143  			vars: []string{"var1" + uint64VarSuffixHigh, "var1" + uint64VarSuffixLow},
   144  			fn: func(values Values) ProgramDesc {
   145  				return ProgramDesc{
   146  					Rules: []seccomp.RuleSet{{
   147  						Rules: seccomp.NewSyscallRules().Add(
   148  							unix.SYS_READ,
   149  							seccomp.PerArg{
   150  								seccomp.EqualTo(values.GetUint64("var1")),
   151  							},
   152  						),
   153  						Action: linux.SECCOMP_RET_ALLOW,
   154  					}},
   155  					SeccompOptions: seccomp.DefaultProgramOptions(),
   156  				}
   157  			},
   158  		},
   159  		{
   160  			name: "inconsistent offsets",
   161  			vars: []string{"var1"},
   162  			fn: func(values Values) ProgramDesc {
   163  				var pa seccomp.PerArg
   164  				if counter == 0 {
   165  					pa[0] = seccomp.EqualTo(values["var1"])
   166  				}
   167  				if counter == 1 {
   168  					pa[0] = seccomp.EqualTo(values["var1"])
   169  					pa[1] = seccomp.EqualTo(values["var1"])
   170  				}
   171  				counter++
   172  				return ProgramDesc{
   173  					Rules: []seccomp.RuleSet{{
   174  						Rules: seccomp.NewSyscallRules().Add(
   175  							unix.SYS_READ,
   176  							pa,
   177  						),
   178  						Action: linux.SECCOMP_RET_ALLOW,
   179  					}},
   180  					SeccompOptions: seccomp.DefaultProgramOptions(),
   181  				}
   182  			},
   183  			wantErr: true,
   184  		},
   185  		{
   186  			name: "inconsistent program size",
   187  			vars: []string{"var1"},
   188  			fn: func(values Values) ProgramDesc {
   189  				pa := seccomp.PerArg{seccomp.EqualTo(values["var1"])}
   190  				if counter == 1 {
   191  					pa[1] = seccomp.EqualTo(123)
   192  				}
   193  				counter++
   194  				return ProgramDesc{
   195  					Rules: []seccomp.RuleSet{{
   196  						Rules: seccomp.NewSyscallRules().Add(
   197  							unix.SYS_READ,
   198  							pa,
   199  						),
   200  						Action: linux.SECCOMP_RET_ALLOW,
   201  					}},
   202  					SeccompOptions: seccomp.DefaultProgramOptions(),
   203  				}
   204  			},
   205  			wantErr: true,
   206  		},
   207  		{
   208  			name: "inconsistent program bytecode",
   209  			vars: []string{"var1"},
   210  			fn: func(values Values) ProgramDesc {
   211  				pa := seccomp.PerArg{seccomp.EqualTo(values["var1"])}
   212  				if counter == 0 {
   213  					pa[1] = seccomp.EqualTo(1337)
   214  				}
   215  				if counter == 1 {
   216  					pa[1] = seccomp.EqualTo(42)
   217  				}
   218  				counter++
   219  				return ProgramDesc{
   220  					Rules: []seccomp.RuleSet{{
   221  						Rules: seccomp.NewSyscallRules().Add(
   222  							unix.SYS_READ,
   223  							pa,
   224  						),
   225  						Action: linux.SECCOMP_RET_ALLOW,
   226  					}},
   227  					SeccompOptions: seccomp.DefaultProgramOptions(),
   228  				}
   229  			},
   230  			wantErr: true,
   231  		},
   232  	} {
   233  		t.Run(test.name, func(t *testing.T) {
   234  			counter = 0
   235  			_, err := Precompile("", test.vars, test.fn)
   236  			if err != nil && !test.wantErr {
   237  				t.Fatalf("Precompile failed: %v", err)
   238  			}
   239  			if err == nil && test.wantErr {
   240  				t.Fatal("Precompile succeeded but want error")
   241  			}
   242  		})
   243  	}
   244  }
   245  
   246  func TestUint64Var(t *testing.T) {
   247  	vars := Values{}
   248  	for _, v := range []uint64{
   249  		0, 1,
   250  		math.MaxInt,
   251  		math.MaxInt16,
   252  		math.MaxInt32,
   253  		math.MaxInt64,
   254  		math.MaxUint64,
   255  	} {
   256  		vars.SetUint64(fmt.Sprintf("var%d", v), v)
   257  		if vars.GetUint64(fmt.Sprintf("var%d", v)) != v {
   258  			t.Errorf("GetUint64(%q) = %d, want %d", fmt.Sprintf("var%d", v), v, v)
   259  		}
   260  	}
   261  }