From 025cff180cb412ec49a85b99c60b8ce2e267704b Mon Sep 17 00:00:00 2001 From: Zach Koopmans Date: Fri, 16 Apr 2021 14:26:29 -0700 Subject: Internal change PiperOrigin-RevId: 368919504 --- runsc/cmd/BUILD | 1 + runsc/cmd/mitigate.go | 49 ++++++++++++++++++++--------------------- runsc/cmd/mitigate_extras.go | 33 +++++++++++++++++++++++++++ runsc/cmd/mitigate_test.go | 7 ------ runsc/mitigate/mitigate.go | 5 +++-- runsc/mitigate/mitigate_test.go | 13 ++++------- runsc/mitigate/mock/mock.go | 31 ++++++++++++++++++-------- 7 files changed, 87 insertions(+), 52 deletions(-) create mode 100644 runsc/cmd/mitigate_extras.go diff --git a/runsc/cmd/BUILD b/runsc/cmd/BUILD index 4b9987cf6..39c8ff603 100644 --- a/runsc/cmd/BUILD +++ b/runsc/cmd/BUILD @@ -23,6 +23,7 @@ go_library( "kill.go", "list.go", "mitigate.go", + "mitigate_extras.go", "path.go", "pause.go", "ps.go", diff --git a/runsc/cmd/mitigate.go b/runsc/cmd/mitigate.go index fddf0e0dd..d37ab80ba 100644 --- a/runsc/cmd/mitigate.go +++ b/runsc/cmd/mitigate.go @@ -40,8 +40,8 @@ type Mitigate struct { reverse bool // Path to file to read to create CPUSet. path string - // Callback to check if a given thread is vulnerable. - vulnerable func(other mitigate.Thread) bool + // Extra data for post mitigate operations. + data string } // Name implements subcommands.command.name. @@ -54,19 +54,20 @@ func (*Mitigate) Synopsis() string { return "mitigate mitigates the underlying system against side channel attacks" } -// Usage implments Usage for cmd.Mitigate. +// Usage implements Usage for cmd.Mitigate. func (m Mitigate) Usage() string { - return `mitigate [flags] + return fmt.Sprintf(`mitigate [flags] mitigate mitigates a system to the "MDS" vulnerability by implementing a manual shutdown of SMT. The command checks /proc/cpuinfo for cpus having the MDS vulnerability, and if found, shutdown all but one CPU per hyperthread pair via /sys/devices/system/cpu/cpu{N}/online. CPUs can be restored by writing "2" to each file in /sys/devices/system/cpu/cpu{N}/online or performing a system reboot. -The command can be reversed with --reverse, which reads the total CPUs from /sys/devices/system/cpu/possible and enables all with /sys/devices/system/cpu/cpu{N}/online.` +The command can be reversed with --reverse, which reads the total CPUs from /sys/devices/system/cpu/possible and enables all with /sys/devices/system/cpu/cpu{N}/online.%s`, m.usage()) } // SetFlags sets flags for the command Mitigate. func (m *Mitigate) SetFlags(f *flag.FlagSet) { f.BoolVar(&m.dryRun, "dryrun", false, "run the command without changing system") f.BoolVar(&m.reverse, "reverse", false, "reverse mitigate by enabling all CPUs") + m.setFlags(f) } // Execute implements subcommands.Command.Execute. @@ -81,13 +82,17 @@ func (m *Mitigate) Execute(_ context.Context, f *flag.FlagSet, args ...interface m.path = allPossibleCPUs } - m.vulnerable = func(other mitigate.Thread) bool { - return other.IsVulnerable() + set, err := m.doExecute() + if err != nil { + return Errorf("Execute failed: %v", err) + } + + if m.data == "" { + return subcommands.ExitSuccess } - if _, err := m.doExecute(); err != nil { - log.Warningf("Execute failed: %v", err) - return subcommands.ExitFailure + if err = m.postMitigate(set); err != nil { + return Errorf("Post Mitigate failed: %v", err) } return subcommands.ExitSuccess @@ -98,32 +103,26 @@ func (m *Mitigate) doExecute() (mitigate.CPUSet, error) { if m.dryRun { log.Infof("Running with DryRun. No cpu settings will be changed.") } + data, err := ioutil.ReadFile(m.path) + if err != nil { + return nil, fmt.Errorf("failed to read %s: %w", m.path, err) + } if m.reverse { - data, err := ioutil.ReadFile(m.path) - if err != nil { - return nil, fmt.Errorf("failed to read %s: %v", m.path, err) - } - set, err := m.doReverse(data) if err != nil { - return nil, fmt.Errorf("reverse operation failed: %v", err) + return nil, fmt.Errorf("reverse operation failed: %w", err) } return set, nil } - - data, err := ioutil.ReadFile(m.path) - if err != nil { - return nil, fmt.Errorf("failed to read %s: %v", m.path, err) - } set, err := m.doMitigate(data) if err != nil { - return nil, fmt.Errorf("mitigate operation failed: %v", err) + return nil, fmt.Errorf("mitigate operation failed: %w", err) } return set, nil } func (m *Mitigate) doMitigate(data []byte) (mitigate.CPUSet, error) { - set, err := mitigate.NewCPUSet(data, m.vulnerable) + set, err := mitigate.NewCPUSet(data) if err != nil { return nil, err } @@ -139,7 +138,7 @@ func (m *Mitigate) doMitigate(data []byte) (mitigate.CPUSet, error) { continue } if err := t.Disable(); err != nil { - return nil, fmt.Errorf("error disabling thread: %s err: %v", t, err) + return nil, fmt.Errorf("error disabling thread: %s err: %w", t, err) } } log.Infof("Shutdown successful.") @@ -164,7 +163,7 @@ func (m *Mitigate) doReverse(data []byte) (mitigate.CPUSet, error) { continue } if err := t.Enable(); err != nil { - return nil, fmt.Errorf("error enabling thread: %s err: %v", t, err) + return nil, fmt.Errorf("error enabling thread: %s err: %w", t, err) } } log.Infof("Enable successful.") diff --git a/runsc/cmd/mitigate_extras.go b/runsc/cmd/mitigate_extras.go new file mode 100644 index 000000000..2cb2833f0 --- /dev/null +++ b/runsc/cmd/mitigate_extras.go @@ -0,0 +1,33 @@ +// 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 cmd + +import ( + "gvisor.dev/gvisor/runsc/flag" + "gvisor.dev/gvisor/runsc/mitigate" +) + +// usage returns any extra bits of the usage string. +func (m *Mitigate) usage() string { + return "" +} + +// setFlags sets extra flags for the command Mitigate. +func (m *Mitigate) setFlags(f *flag.FlagSet) {} + +// postMitigate handles any postMitigate actions. +func (m *Mitigate) postMitigate(_ mitigate.CPUSet) error { + return nil +} diff --git a/runsc/cmd/mitigate_test.go b/runsc/cmd/mitigate_test.go index 163fece42..5a76667e3 100644 --- a/runsc/cmd/mitigate_test.go +++ b/runsc/cmd/mitigate_test.go @@ -21,7 +21,6 @@ import ( "strings" "testing" - "gvisor.dev/gvisor/runsc/mitigate" "gvisor.dev/gvisor/runsc/mitigate/mock" ) @@ -84,9 +83,6 @@ power management::84 t.Run(tc.name, func(t *testing.T) { m := &Mitigate{ dryRun: true, - vulnerable: func(other mitigate.Thread) bool { - return other.IsVulnerable() - }, } m.doExecuteTest(t, "Mitigate", tc.mitigateData, tc.mitigateCPU, tc.mitigateError) @@ -104,9 +100,6 @@ func TestExecuteSmoke(t *testing.T) { m := &Mitigate{ dryRun: true, - vulnerable: func(other mitigate.Thread) bool { - return other.IsVulnerable() - }, } m.doExecuteTest(t, "Mitigate", string(smokeMitigate), 0, nil) diff --git a/runsc/mitigate/mitigate.go b/runsc/mitigate/mitigate.go index 24f67414c..88409af8f 100644 --- a/runsc/mitigate/mitigate.go +++ b/runsc/mitigate/mitigate.go @@ -50,7 +50,7 @@ const ( type CPUSet map[threadID]*ThreadGroup // NewCPUSet creates a CPUSet from data read from /proc/cpuinfo. -func NewCPUSet(data []byte, vulnerable func(Thread) bool) (CPUSet, error) { +func NewCPUSet(data []byte) (CPUSet, error) { processors, err := getThreads(string(data)) if err != nil { return nil, err @@ -67,7 +67,7 @@ func NewCPUSet(data []byte, vulnerable func(Thread) bool) (CPUSet, error) { core = &ThreadGroup{} set[p.id] = core } - core.isVulnerable = core.isVulnerable || vulnerable(p) + core.isVulnerable = core.isVulnerable || p.IsVulnerable() core.threads = append(core.threads, p) } @@ -446,6 +446,7 @@ func buildRegex(key, match string) *regexp.Regexp { 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 %q: %q", key, data) } diff --git a/runsc/mitigate/mitigate_test.go b/runsc/mitigate/mitigate_test.go index fbd8eb886..3bf9ef547 100644 --- a/runsc/mitigate/mitigate_test.go +++ b/runsc/mitigate/mitigate_test.go @@ -52,14 +52,13 @@ func TestMockCPUSet(t *testing.T) { } { t.Run(tc.testCase.Name, func(t *testing.T) { data := tc.testCase.MakeCPUString() - vulnerable := func(t Thread) bool { - return t.IsVulnerable() - } - set, err := NewCPUSet([]byte(data), vulnerable) + set, err := NewCPUSet([]byte(data)) if err != nil { t.Fatalf("Failed to create cpuSet: %v", err) } + t.Logf("data: %s", data) + for _, tg := range set { if err := checkSorted(tg.threads); err != nil { t.Fatalf("Failed to sort cpuSet: %v", err) @@ -258,11 +257,7 @@ func TestReadFile(t *testing.T) { t.Fatalf("Failed to read cpuinfo: %v", err) } - vulnerable := func(t Thread) bool { - return t.IsVulnerable() - } - - set, err := NewCPUSet(data, vulnerable) + set, err := NewCPUSet(data) if err != nil { t.Fatalf("Failed to parse CPU data %v\n%s", err, data) } diff --git a/runsc/mitigate/mock/mock.go b/runsc/mitigate/mock/mock.go index 2db718cb9..12c59e356 100644 --- a/runsc/mitigate/mock/mock.go +++ b/runsc/mitigate/mock/mock.go @@ -82,6 +82,19 @@ var Haswell2core = CPU{ ThreadsPerCore: 1, } +// AMD2 is an two core AMD machine. +var AMD2 = CPU{ + Name: "AMD", + VendorID: "AuthenticAMD", + Family: 23, + Model: 49, + ModelName: "AMD EPYC 7B12", + Bugs: "sysret_ss_attrs spectre_v1 spectre_v2 spec_store_bypass", + PhysicalCores: 1, + Cores: 1, + ThreadsPerCore: 2, +} + // AMD8 is an eight core AMD machine. var AMD8 = CPU{ Name: "AMD", @@ -115,15 +128,15 @@ bugs : %s for k := 0; k < tc.ThreadsPerCore; k++ { processorNum := (i*tc.Cores+j)*tc.ThreadsPerCore + k ret += fmt.Sprintf(template, - processorNum, /*processor*/ - tc.VendorID, /*vendor_id*/ - tc.Family, /*cpu family*/ - tc.Model, /*model*/ - tc.ModelName, /*model name*/ - i, /*physical id*/ - j, /*core id*/ - tc.Cores*tc.PhysicalCores, /*cpu cores*/ - tc.Bugs, /*bugs*/ + processorNum, /*processor*/ + tc.VendorID, /*vendor_id*/ + tc.Family, /*cpu family*/ + tc.Model, /*model*/ + tc.ModelName, /*model name*/ + i, /*physical id*/ + j, /*core id*/ + k, /*cpu cores*/ + tc.Bugs, /*bugs*/ ) } } -- cgit v1.2.3