gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/runsc/mitigate/mitigate_test.go (about) 1 // Copyright 2021 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 //go:build amd64 16 // +build amd64 17 18 package mitigate 19 20 import ( 21 "io/ioutil" 22 "strings" 23 "testing" 24 ) 25 26 // TestMockCPUSet tests mock cpu test cases against the cpuSet functions. 27 func TestMockCPUSet(t *testing.T) { 28 for _, tc := range []struct { 29 testCase MockCPU 30 isVulnerable bool 31 }{ 32 { 33 testCase: AMD8, 34 isVulnerable: false, 35 }, 36 { 37 testCase: Haswell2, 38 isVulnerable: true, 39 }, 40 { 41 testCase: Haswell2core, 42 isVulnerable: true, 43 }, 44 { 45 testCase: CascadeLake2, 46 isVulnerable: true, 47 }, 48 { 49 testCase: CascadeLake4, 50 isVulnerable: true, 51 }, 52 } { 53 t.Run(tc.testCase.Name, func(t *testing.T) { 54 data := tc.testCase.MakeCPUSet().String() 55 set, err := NewCPUSet(data) 56 if err != nil { 57 t.Fatalf("Failed to create cpuSet: %v", err) 58 } 59 60 if tc.testCase.NumCPUs() != len(set) { 61 t.Fatalf("Got wrong number of CPUs: want: %d got: %d", tc.testCase.NumCPUs(), len(set)) 62 } 63 64 if set.IsVulnerable() != tc.isVulnerable { 65 t.Fatalf("incorrect vulnerable value: got: %t want: %t", set.IsVulnerable(), tc.isVulnerable) 66 } 67 t.Logf("data: %s", data) 68 }) 69 } 70 } 71 72 // TestGetCPU tests basic parsing of single CPU strings from reading 73 // /proc/cpuinfo. 74 func TestGetCPU(t *testing.T) { 75 data := `processor : 0 76 vendor_id : GenuineIntel 77 cpu family : 6 78 model : 85 79 physical id: 0 80 core id : 0 81 bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs taa itlb_multihit 82 ` 83 want := CPU{ 84 processorNumber: 0, 85 vendorID: "GenuineIntel", 86 cpuFamily: 6, 87 model: 85, 88 physicalID: 0, 89 coreID: 0, 90 bugs: map[string]struct{}{ 91 "cpu_meltdown": {}, 92 "spectre_v1": {}, 93 "spectre_v2": {}, 94 "spec_store_bypass": {}, 95 "l1tf": {}, 96 "mds": {}, 97 "swapgs": {}, 98 "taa": {}, 99 "itlb_multihit": {}, 100 }, 101 } 102 103 got, err := newCPU(data) 104 if err != nil { 105 t.Fatalf("getCpu failed with error: %v", err) 106 } 107 108 if !want.SimilarTo(got) { 109 t.Fatalf("Failed cpus not similar: got: %+v, want: %+v", got, want) 110 } 111 112 if !got.IsVulnerable() { 113 t.Fatalf("Failed: cpu should be vulnerable.") 114 } 115 } 116 117 func TestInvalid(t *testing.T) { 118 result, err := newCPU(`something not a processor`) 119 if err == nil { 120 t.Fatalf("getCPU set didn't return an error: %+v", result) 121 } 122 123 if !strings.Contains(err.Error(), "failed to match key \"processor\"") { 124 t.Fatalf("Incorrect error returned: %v", err) 125 } 126 } 127 128 // TestCPUSet tests getting the right number of CPUs from 129 // parsing full output of /proc/cpuinfo. 130 func TestCPUSet(t *testing.T) { 131 data := `processor : 0 132 vendor_id : GenuineIntel 133 cpu family : 6 134 model : 63 135 model name : Intel(R) Xeon(R) CPU @ 2.30GHz 136 stepping : 0 137 microcode : 0x1 138 cpu MHz : 2299.998 139 cache size : 46080 KB 140 physical id : 0 141 siblings : 2 142 core id : 0 143 cpu cores : 1 144 apicid : 0 145 initial apicid : 0 146 fpu : yes 147 fpu_exception : yes 148 cpuid level : 13 149 wp : yes 150 flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm invpcid_single pti ssbd ibrs ibpb stibp fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt arat md_clear arch_capabilities 151 bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs 152 bogomips : 4599.99 153 clflush size : 64 154 cache_alignment : 64 155 address sizes : 46 bits physical, 48 bits virtual 156 power management: 157 158 processor : 1 159 vendor_id : GenuineIntel 160 cpu family : 6 161 model : 63 162 model name : Intel(R) Xeon(R) CPU @ 2.30GHz 163 stepping : 0 164 microcode : 0x1 165 cpu MHz : 2299.998 166 cache size : 46080 KB 167 physical id : 0 168 siblings : 2 169 core id : 0 170 cpu cores : 1 171 apicid : 1 172 initial apicid : 1 173 fpu : yes 174 fpu_exception : yes 175 cpuid level : 13 176 wp : yes 177 flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm invpcid_single pti ssbd ibrs ibpb stibp fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt arat md_clear arch_capabilities 178 bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs 179 bogomips : 4599.99 180 clflush size : 64 181 cache_alignment : 64 182 address sizes : 46 bits physical, 48 bits virtual 183 power management: 184 ` 185 cpuSet, err := NewCPUSet(data) 186 if err != nil { 187 t.Fatalf("getCPUSet failed: %v", err) 188 } 189 190 wantCPULen := 2 191 if len(cpuSet) != wantCPULen { 192 t.Fatalf("Num CPU mismatch: want: %d, got: %d", wantCPULen, len(cpuSet)) 193 } 194 195 wantCPU := CPU{ 196 vendorID: "GenuineIntel", 197 cpuFamily: 6, 198 model: 63, 199 bugs: map[string]struct{}{ 200 "cpu_meltdown": {}, 201 "spectre_v1": {}, 202 "spectre_v2": {}, 203 "spec_store_bypass": {}, 204 "l1tf": {}, 205 "mds": {}, 206 "swapgs": {}, 207 }, 208 } 209 210 for _, c := range cpuSet { 211 if !wantCPU.SimilarTo(c) { 212 t.Fatalf("Failed cpus not equal: got: %+v, want: %+v", c, wantCPU) 213 } 214 } 215 } 216 217 // TestReadFile is a smoke test for parsing methods. 218 func TestReadFile(t *testing.T) { 219 data, err := ioutil.ReadFile("/proc/cpuinfo") 220 if err != nil { 221 t.Fatalf("Failed to read cpuinfo: %v", err) 222 } 223 224 set, err := NewCPUSet(string(data)) 225 if err != nil { 226 t.Fatalf("Failed to parse CPU data %v\n%s", err, data) 227 } 228 229 if len(set) < 1 { 230 t.Fatalf("Failed to parse any CPUs: %d", len(set)) 231 } 232 233 t.Log(set) 234 } 235 236 // TestVulnerable tests if the isVulnerable method is correct 237 // among known CPUs in GCP. 238 func TestVulnerable(t *testing.T) { 239 const haswell = `processor : 0 240 vendor_id : GenuineIntel 241 cpu family : 6 242 model : 63 243 model name : Intel(R) Xeon(R) CPU @ 2.30GHz 244 stepping : 0 245 microcode : 0x1 246 cpu MHz : 2299.998 247 cache size : 46080 KB 248 physical id : 0 249 siblings : 4 250 core id : 0 251 cpu cores : 2 252 apicid : 0 253 initial apicid : 0 254 fpu : yes 255 fpu_exception : yes 256 cpuid level : 13 257 wp : yes 258 flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm invpcid_single pti ssbd ibrs ibpb stibp fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt arat md_clear arch_capabilities 259 bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs 260 bogomips : 4599.99 261 clflush size : 64 262 cache_alignment : 64 263 address sizes : 46 bits physical, 48 bits virtual 264 power management:` 265 266 const skylake = `processor : 0 267 vendor_id : GenuineIntel 268 cpu family : 6 269 model : 85 270 model name : Intel(R) Xeon(R) CPU @ 2.00GHz 271 stepping : 3 272 microcode : 0x1 273 cpu MHz : 2000.180 274 cache size : 39424 KB 275 physical id : 0 276 siblings : 2 277 core id : 0 278 cpu cores : 1 279 apicid : 0 280 initial apicid : 0 281 fpu : yes 282 fpu_exception : yes 283 cpuid level : 13 284 wp : yes 285 flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single pti ssbd ibrs ibpb stibp fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat md_clear arch_capabilities 286 bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs taa 287 bogomips : 4000.36 288 clflush size : 64 289 cache_alignment : 64 290 address sizes : 46 bits physical, 48 bits virtual 291 power management:` 292 293 const amd = `processor : 0 294 vendor_id : AuthenticAMD 295 cpu family : 23 296 model : 49 297 model name : AMD EPYC 7B12 298 stepping : 0 299 microcode : 0x1000065 300 cpu MHz : 2250.000 301 cache size : 512 KB 302 physical id : 0 303 siblings : 2 304 core id : 0 305 cpu cores : 1 306 apicid : 0 307 initial apicid : 0 308 fpu : yes 309 fpu_exception : yes 310 cpuid level : 13 311 wp : yes 312 flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid extd_apicid tsc_known_freq pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm cmp_legacy cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw topoext ssbd ibrs ibpb stibp vmmcall fsgsbase tsc_adjust bmi1 avx2 smep bmi2 rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 clzero xsaveerptr arat npt nrip_save umip rdpid 313 bugs : sysret_ss_attrs spectre_v1 spectre_v2 spec_store_bypass 314 bogomips : 4500.00 315 TLB size : 3072 4K pages 316 clflush size : 64 317 cache_alignment : 64 318 address sizes : 48 bits physical, 48 bits virtual 319 power management:` 320 321 for _, tc := range []struct { 322 name string 323 cpuString string 324 vulnerable bool 325 }{ 326 { 327 name: "haswell", 328 cpuString: haswell, 329 vulnerable: true, 330 }, { 331 name: "skylake", 332 cpuString: skylake, 333 vulnerable: true, 334 }, { 335 name: "amd", 336 cpuString: amd, 337 vulnerable: false, 338 }, 339 } { 340 t.Run(tc.name, func(t *testing.T) { 341 set, err := NewCPUSet(tc.cpuString) 342 if err != nil { 343 t.Fatalf("Failed to getCPUSet:%v\n %s", err, tc.cpuString) 344 } 345 346 if len(set) < 1 { 347 t.Fatalf("Returned empty cpu set: %v", set) 348 } 349 350 for _, c := range set { 351 got := func() bool { 352 return c.IsVulnerable() 353 }() 354 355 if got != tc.vulnerable { 356 t.Fatalf("Mismatch vulnerable for cpu %s: got %t want: %t", tc.name, tc.vulnerable, got) 357 } 358 } 359 }) 360 } 361 }