mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add initial mitigate code and cpu parsing.
PiperOrigin-RevId: 353274135
This commit is contained in:
committed by
gVisor bot
parent
9b4f4655ed
commit
16b81308cf
@@ -0,0 +1,18 @@
|
||||
load("//tools:defs.bzl", "go_library", "go_test")
|
||||
|
||||
package(licenses = ["notice"])
|
||||
|
||||
go_library(
|
||||
name = "mitigate",
|
||||
srcs = [
|
||||
"cpu.go",
|
||||
"mitigate.go",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "mitigate_test",
|
||||
size = "small",
|
||||
srcs = ["cpu_test.go"],
|
||||
library = ":mitigate",
|
||||
)
|
||||
@@ -0,0 +1,235 @@
|
||||
// Copyright 2021 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package mitigate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// constants of coomm
|
||||
meltdown = "cpu_meltdown"
|
||||
l1tf = "l1tf"
|
||||
mds = "mds"
|
||||
swapgs = "swapgs"
|
||||
taa = "taa"
|
||||
)
|
||||
|
||||
const (
|
||||
processorKey = "processor"
|
||||
vendorIDKey = "vendor_id"
|
||||
cpuFamilyKey = "cpu family"
|
||||
modelKey = "model"
|
||||
coreIDKey = "core id"
|
||||
bugsKey = "bugs"
|
||||
)
|
||||
|
||||
// getCPUSet returns cpu structs from reading /proc/cpuinfo.
|
||||
func getCPUSet(data string) ([]*cpu, error) {
|
||||
// Each processor entry should start with the
|
||||
// processor key. Find the beginings of each.
|
||||
r := buildRegex(processorKey, `\d+`)
|
||||
indices := r.FindAllStringIndex(data, -1)
|
||||
if len(indices) < 1 {
|
||||
return nil, fmt.Errorf("no cpus found for: %s", data)
|
||||
}
|
||||
|
||||
// Add the ending index for last entry.
|
||||
indices = append(indices, []int{len(data), -1})
|
||||
|
||||
// Valid cpus are now defined by strings in between
|
||||
// indexes (e.g. data[index[i], index[i+1]]).
|
||||
// There should be len(indicies) - 1 CPUs
|
||||
// since the last index is the end of the string.
|
||||
var cpus = make([]*cpu, 0, len(indices)-1)
|
||||
// Find each string that represents a CPU. These begin "processor".
|
||||
for i := 1; i < len(indices); i++ {
|
||||
start := indices[i-1][0]
|
||||
end := indices[i][0]
|
||||
// Parse the CPU entry, which should be between start/end.
|
||||
c, err := getCPU(data[start:end])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cpus = append(cpus, c)
|
||||
}
|
||||
return cpus, nil
|
||||
}
|
||||
|
||||
// type cpu represents pertinent info about a cpu.
|
||||
type cpu struct {
|
||||
processorNumber int64 // the processor number of this CPU.
|
||||
vendorID string // the vendorID of CPU (e.g. AuthenticAMD).
|
||||
cpuFamily int64 // CPU family number (e.g. 6 for CascadeLake/Skylake).
|
||||
model int64 // CPU model number (e.g. 85 for CascadeLake/Skylake).
|
||||
coreID int64 // This CPU's core id to match Hyperthread Pairs
|
||||
bugs map[string]struct{} // map of vulnerabilities parsed from the 'bugs' field.
|
||||
}
|
||||
|
||||
// getCPU parses a CPU from a single cpu entry from /proc/cpuinfo.
|
||||
func getCPU(data string) (*cpu, error) {
|
||||
processor, err := parseProcessor(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vendorID, err := parseVendorID(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cpuFamily, err := parseCPUFamily(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
model, err := parseModel(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
coreID, err := parseCoreID(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bugs, err := parseBugs(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &cpu{
|
||||
processorNumber: processor,
|
||||
vendorID: vendorID,
|
||||
cpuFamily: cpuFamily,
|
||||
model: model,
|
||||
coreID: coreID,
|
||||
bugs: bugs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// List of pertinent side channel vulnerablilites.
|
||||
// For mds, see: https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/mds.html.
|
||||
var vulnerabilities = []string{
|
||||
meltdown,
|
||||
l1tf,
|
||||
mds,
|
||||
swapgs,
|
||||
taa,
|
||||
}
|
||||
|
||||
// isVulnerable checks if a CPU is vulnerable to pertinent bugs.
|
||||
func (c *cpu) isVulnerable() bool {
|
||||
for _, bug := range vulnerabilities {
|
||||
if _, ok := c.bugs[bug]; ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// similarTo checks family/model/bugs fields for equality of two
|
||||
// processors.
|
||||
func (c *cpu) similarTo(other *cpu) bool {
|
||||
if c.vendorID != other.vendorID {
|
||||
return false
|
||||
}
|
||||
|
||||
if other.cpuFamily != c.cpuFamily {
|
||||
return false
|
||||
}
|
||||
|
||||
if other.model != c.model {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(other.bugs) != len(c.bugs) {
|
||||
return false
|
||||
}
|
||||
|
||||
for bug := range c.bugs {
|
||||
if _, ok := other.bugs[bug]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// parseProcessor grabs the processor field from /proc/cpuinfo output.
|
||||
func parseProcessor(data string) (int64, error) {
|
||||
return parseIntegerResult(data, processorKey)
|
||||
}
|
||||
|
||||
// parseVendorID grabs the vendor_id field from /proc/cpuinfo output.
|
||||
func parseVendorID(data string) (string, error) {
|
||||
return parseRegex(data, vendorIDKey, `[\w\d]+`)
|
||||
}
|
||||
|
||||
// parseCPUFamily grabs the cpu family field from /proc/cpuinfo output.
|
||||
func parseCPUFamily(data string) (int64, error) {
|
||||
return parseIntegerResult(data, cpuFamilyKey)
|
||||
}
|
||||
|
||||
// parseModel grabs the model field from /proc/cpuinfo output.
|
||||
func parseModel(data string) (int64, error) {
|
||||
return parseIntegerResult(data, modelKey)
|
||||
}
|
||||
|
||||
// parseCoreID parses the core id field.
|
||||
func parseCoreID(data string) (int64, error) {
|
||||
return parseIntegerResult(data, coreIDKey)
|
||||
}
|
||||
|
||||
// parseBugs grabs the bugs field from /proc/cpuinfo output.
|
||||
func parseBugs(data string) (map[string]struct{}, error) {
|
||||
result, err := parseRegex(data, bugsKey, `[\d\w\s]*`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bugs := strings.Split(result, " ")
|
||||
ret := make(map[string]struct{}, len(bugs))
|
||||
for _, bug := range bugs {
|
||||
ret[bug] = struct{}{}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// parseIntegerResult parses fields expecting an integer.
|
||||
func parseIntegerResult(data, key string) (int64, error) {
|
||||
result, err := parseRegex(data, key, `\d+`)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return strconv.ParseInt(result, 0, 64)
|
||||
}
|
||||
|
||||
// buildRegex builds a regex for parsing each CPU field.
|
||||
func buildRegex(key, match string) *regexp.Regexp {
|
||||
reg := fmt.Sprintf(`(?m)^%s\s*:\s*(.*)$`, key)
|
||||
return regexp.MustCompile(reg)
|
||||
}
|
||||
|
||||
// parseRegex parses data with key inserted into a standard regex template.
|
||||
func parseRegex(data, key, match string) (string, error) {
|
||||
r := buildRegex(key, match)
|
||||
matches := r.FindStringSubmatch(data)
|
||||
if len(matches) < 2 {
|
||||
return "", fmt.Errorf("failed to match key %s: %s", key, data)
|
||||
}
|
||||
return matches[1], nil
|
||||
}
|
||||
@@ -0,0 +1,368 @@
|
||||
// Copyright 2021 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package mitigate
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// CPU info for a Intel CascadeLake processor. Both Skylake and CascadeLake have
|
||||
// the same family/model numbers, but with different bugs (e.g. skylake has
|
||||
// cpu_meltdown).
|
||||
var cascadeLake = &cpu{
|
||||
vendorID: "GenuineIntel",
|
||||
cpuFamily: 6,
|
||||
model: 85,
|
||||
bugs: map[string]struct{}{
|
||||
"spectre_v1": struct{}{},
|
||||
"spectre_v2": struct{}{},
|
||||
"spec_store_bypass": struct{}{},
|
||||
mds: struct{}{},
|
||||
swapgs: struct{}{},
|
||||
taa: struct{}{},
|
||||
},
|
||||
}
|
||||
|
||||
// TestGetCPU tests basic parsing of single CPU strings from reading
|
||||
// /proc/cpuinfo.
|
||||
func TestGetCPU(t *testing.T) {
|
||||
data := `processor : 0
|
||||
vendor_id : GenuineIntel
|
||||
cpu family : 6
|
||||
model : 85
|
||||
core id : 0
|
||||
bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs taa itlb_multihit
|
||||
`
|
||||
want := cpu{
|
||||
processorNumber: 0,
|
||||
vendorID: "GenuineIntel",
|
||||
cpuFamily: 6,
|
||||
model: 85,
|
||||
coreID: 0,
|
||||
bugs: map[string]struct{}{
|
||||
"cpu_meltdown": struct{}{},
|
||||
"spectre_v1": struct{}{},
|
||||
"spectre_v2": struct{}{},
|
||||
"spec_store_bypass": struct{}{},
|
||||
"l1tf": struct{}{},
|
||||
"mds": struct{}{},
|
||||
"swapgs": struct{}{},
|
||||
"taa": struct{}{},
|
||||
"itlb_multihit": struct{}{},
|
||||
},
|
||||
}
|
||||
|
||||
got, err := getCPU(data)
|
||||
if err != nil {
|
||||
t.Fatalf("getCpu failed with error: %v", err)
|
||||
}
|
||||
|
||||
if !want.similarTo(got) {
|
||||
t.Fatalf("Failed cpus not similar: got: %+v, want: %+v", got, want)
|
||||
}
|
||||
|
||||
if !got.isVulnerable() {
|
||||
t.Fatalf("Failed: cpu should be vulnerable.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalid(t *testing.T) {
|
||||
result, err := getCPUSet(`something not a processor`)
|
||||
if err == nil {
|
||||
t.Fatalf("getCPU set didn't return an error: %+v", result)
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), "no cpus") {
|
||||
t.Fatalf("Incorrect error returned: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestCPUSet tests getting the right number of CPUs from
|
||||
// parsing full output of /proc/cpuinfo.
|
||||
func TestCPUSet(t *testing.T) {
|
||||
data := `processor : 0
|
||||
vendor_id : GenuineIntel
|
||||
cpu family : 6
|
||||
model : 63
|
||||
model name : Intel(R) Xeon(R) CPU @ 2.30GHz
|
||||
stepping : 0
|
||||
microcode : 0x1
|
||||
cpu MHz : 2299.998
|
||||
cache size : 46080 KB
|
||||
physical id : 0
|
||||
siblings : 2
|
||||
core id : 0
|
||||
cpu cores : 1
|
||||
apicid : 0
|
||||
initial apicid : 0
|
||||
fpu : yes
|
||||
fpu_exception : yes
|
||||
cpuid level : 13
|
||||
wp : yes
|
||||
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
|
||||
bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs
|
||||
bogomips : 4599.99
|
||||
clflush size : 64
|
||||
cache_alignment : 64
|
||||
address sizes : 46 bits physical, 48 bits virtual
|
||||
power management:
|
||||
|
||||
processor : 1
|
||||
vendor_id : GenuineIntel
|
||||
cpu family : 6
|
||||
model : 63
|
||||
model name : Intel(R) Xeon(R) CPU @ 2.30GHz
|
||||
stepping : 0
|
||||
microcode : 0x1
|
||||
cpu MHz : 2299.998
|
||||
cache size : 46080 KB
|
||||
physical id : 0
|
||||
siblings : 2
|
||||
core id : 0
|
||||
cpu cores : 1
|
||||
apicid : 1
|
||||
initial apicid : 1
|
||||
fpu : yes
|
||||
fpu_exception : yes
|
||||
cpuid level : 13
|
||||
wp : yes
|
||||
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
|
||||
bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs
|
||||
bogomips : 4599.99
|
||||
clflush size : 64
|
||||
cache_alignment : 64
|
||||
address sizes : 46 bits physical, 48 bits virtual
|
||||
power management:
|
||||
`
|
||||
cpuSet, err := getCPUSet(data)
|
||||
if err != nil {
|
||||
t.Fatalf("getCPUSet failed: %v", err)
|
||||
}
|
||||
|
||||
wantCPULen := 2
|
||||
if len(cpuSet) != wantCPULen {
|
||||
t.Fatalf("Num CPU mismatch: want: %d, got: %d", wantCPULen, len(cpuSet))
|
||||
}
|
||||
|
||||
wantCPU := cpu{
|
||||
vendorID: "GenuineIntel",
|
||||
cpuFamily: 6,
|
||||
model: 63,
|
||||
bugs: map[string]struct{}{
|
||||
"cpu_meltdown": struct{}{},
|
||||
"spectre_v1": struct{}{},
|
||||
"spectre_v2": struct{}{},
|
||||
"spec_store_bypass": struct{}{},
|
||||
"l1tf": struct{}{},
|
||||
"mds": struct{}{},
|
||||
"swapgs": struct{}{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cpuSet {
|
||||
if !wantCPU.similarTo(c) {
|
||||
t.Fatalf("Failed cpus not equal: got: %+v, want: %+v", c, wantCPU)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestReadFile is a smoke test for parsing methods.
|
||||
func TestReadFile(t *testing.T) {
|
||||
data, err := ioutil.ReadFile("/proc/cpuinfo")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read cpuinfo: %v", err)
|
||||
}
|
||||
|
||||
set, err := getCPUSet(string(data))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse CPU data %v\n%s", err, data)
|
||||
}
|
||||
|
||||
if len(set) < 1 {
|
||||
t.Fatalf("Failed to parse any CPUs: %d", len(set))
|
||||
}
|
||||
|
||||
for _, c := range set {
|
||||
t.Logf("CPU: %+v: %t", c, c.isVulnerable())
|
||||
}
|
||||
}
|
||||
|
||||
// TestVulnerable tests if the isVulnerable method is correct
|
||||
// among known CPUs in GCP.
|
||||
func TestVulnerable(t *testing.T) {
|
||||
const haswell = `processor : 0
|
||||
vendor_id : GenuineIntel
|
||||
cpu family : 6
|
||||
model : 63
|
||||
model name : Intel(R) Xeon(R) CPU @ 2.30GHz
|
||||
stepping : 0
|
||||
microcode : 0x1
|
||||
cpu MHz : 2299.998
|
||||
cache size : 46080 KB
|
||||
physical id : 0
|
||||
siblings : 4
|
||||
core id : 0
|
||||
cpu cores : 2
|
||||
apicid : 0
|
||||
initial apicid : 0
|
||||
fpu : yes
|
||||
fpu_exception : yes
|
||||
cpuid level : 13
|
||||
wp : yes
|
||||
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
|
||||
bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs
|
||||
bogomips : 4599.99
|
||||
clflush size : 64
|
||||
cache_alignment : 64
|
||||
address sizes : 46 bits physical, 48 bits virtual
|
||||
power management:`
|
||||
|
||||
const skylake = `processor : 0
|
||||
vendor_id : GenuineIntel
|
||||
cpu family : 6
|
||||
model : 85
|
||||
model name : Intel(R) Xeon(R) CPU @ 2.00GHz
|
||||
stepping : 3
|
||||
microcode : 0x1
|
||||
cpu MHz : 2000.180
|
||||
cache size : 39424 KB
|
||||
physical id : 0
|
||||
siblings : 2
|
||||
core id : 0
|
||||
cpu cores : 1
|
||||
apicid : 0
|
||||
initial apicid : 0
|
||||
fpu : yes
|
||||
fpu_exception : yes
|
||||
cpuid level : 13
|
||||
wp : yes
|
||||
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
|
||||
bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs taa
|
||||
bogomips : 4000.36
|
||||
clflush size : 64
|
||||
cache_alignment : 64
|
||||
address sizes : 46 bits physical, 48 bits virtual
|
||||
power management:`
|
||||
|
||||
const cascade = `processor : 0
|
||||
vendor_id : GenuineIntel
|
||||
cpu family : 6
|
||||
model : 85
|
||||
model name : Intel(R) Xeon(R) CPU
|
||||
stepping : 7
|
||||
microcode : 0x1
|
||||
cpu MHz : 2800.198
|
||||
cache size : 33792 KB
|
||||
physical id : 0
|
||||
siblings : 2
|
||||
core id : 0
|
||||
cpu cores : 1
|
||||
apicid : 0
|
||||
initial apicid : 0
|
||||
fpu : yes
|
||||
fpu_exception : yes
|
||||
cpuid level : 13
|
||||
wp : yes
|
||||
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 pclmu
|
||||
lqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowpr
|
||||
efetch invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid r
|
||||
tm mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves a
|
||||
rat avx512_vnni md_clear arch_capabilities
|
||||
bugs : spectre_v1 spectre_v2 spec_store_bypass mds swapgs taa
|
||||
bogomips : 5600.39
|
||||
clflush size : 64
|
||||
cache_alignment : 64
|
||||
address sizes : 46 bits physical, 48 bits virtual
|
||||
power management:`
|
||||
|
||||
const amd = `processor : 0
|
||||
vendor_id : AuthenticAMD
|
||||
cpu family : 23
|
||||
model : 49
|
||||
model name : AMD EPYC 7B12
|
||||
stepping : 0
|
||||
microcode : 0x1000065
|
||||
cpu MHz : 2250.000
|
||||
cache size : 512 KB
|
||||
physical id : 0
|
||||
siblings : 2
|
||||
core id : 0
|
||||
cpu cores : 1
|
||||
apicid : 0
|
||||
initial apicid : 0
|
||||
fpu : yes
|
||||
fpu_exception : yes
|
||||
cpuid level : 13
|
||||
wp : yes
|
||||
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
|
||||
bugs : sysret_ss_attrs spectre_v1 spectre_v2 spec_store_bypass
|
||||
bogomips : 4500.00
|
||||
TLB size : 3072 4K pages
|
||||
clflush size : 64
|
||||
cache_alignment : 64
|
||||
address sizes : 48 bits physical, 48 bits virtual
|
||||
power management:`
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
cpuString string
|
||||
vulnerable bool
|
||||
}{
|
||||
{
|
||||
name: "haswell",
|
||||
cpuString: haswell,
|
||||
vulnerable: true,
|
||||
}, {
|
||||
name: "skylake",
|
||||
cpuString: skylake,
|
||||
vulnerable: true,
|
||||
}, {
|
||||
name: "cascadeLake",
|
||||
cpuString: cascade,
|
||||
vulnerable: false,
|
||||
}, {
|
||||
name: "amd",
|
||||
cpuString: amd,
|
||||
vulnerable: false,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
set, err := getCPUSet(tc.cpuString)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to getCPUSet:%v\n %s", err, tc.cpuString)
|
||||
}
|
||||
|
||||
if len(set) < 1 {
|
||||
t.Fatalf("Returned empty cpu set: %v", set)
|
||||
}
|
||||
|
||||
for _, c := range set {
|
||||
got := func() bool {
|
||||
if cascadeLake.similarTo(c) {
|
||||
return false
|
||||
}
|
||||
return c.isVulnerable()
|
||||
}()
|
||||
|
||||
if got != tc.vulnerable {
|
||||
t.Fatalf("Mismatch vulnerable for cpu %+s: got %t want: %t", tc.name, tc.vulnerable, got)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2021 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package mitigate provides libraries for the mitigate command. The
|
||||
// mitigate command mitigates side channel attacks such as MDS. Mitigate
|
||||
// shuts down CPUs via /sys/devices/system/cpu/cpu{N}/online. In addition,
|
||||
// the mitigate also handles computing available CPU in kubernetes kube_config
|
||||
// files.
|
||||
package mitigate
|
||||
Reference in New Issue
Block a user