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 }