From eb9b8e53a3ef7bb96dcb59a0121fa9ed22f01bfd Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 30 Mar 2021 21:40:07 -0700 Subject: platform/kvm/x86: restore mxcsr when switching from guest to sentry Goruntime sets mxcsr once and never changes it. Reported-by: syzbot+ec55cea6e57ec083b7a6@syzkaller.appspotmail.com Fixes: #5754 --- pkg/sentry/arch/fpu/fpu_amd64.go | 5 +++++ pkg/sentry/platform/kvm/BUILD | 1 + pkg/sentry/platform/kvm/kvm_amd64_test.go | 30 ++++++++++++++++++++++++++++++ pkg/sentry/platform/kvm/kvm_amd64_test.s | 21 +++++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 pkg/sentry/platform/kvm/kvm_amd64_test.s (limited to 'pkg/sentry') diff --git a/pkg/sentry/arch/fpu/fpu_amd64.go b/pkg/sentry/arch/fpu/fpu_amd64.go index 1e9625bee..f0ba26736 100644 --- a/pkg/sentry/arch/fpu/fpu_amd64.go +++ b/pkg/sentry/arch/fpu/fpu_amd64.go @@ -219,6 +219,11 @@ func (s *State) PtraceSetXstateRegs(src io.Reader, maxlen int, featureSet *cpuid return copy(*s, f), nil } +// SetMXCSR sets the MXCSR control/status register in the state. +func (s *State) SetMXCSR(mxcsr uint32) { + hostarch.ByteOrder.PutUint32((*s)[mxcsrOffset:], mxcsr) +} + // BytePointer returns a pointer to the first byte of the state. // //go:nosplit diff --git a/pkg/sentry/platform/kvm/BUILD b/pkg/sentry/platform/kvm/BUILD index f04898dc1..47b294312 100644 --- a/pkg/sentry/platform/kvm/BUILD +++ b/pkg/sentry/platform/kvm/BUILD @@ -66,6 +66,7 @@ go_test( srcs = [ "kvm_amd64_test.go", "kvm_arm64_test.go", + "kvm_amd64_test.s", "kvm_test.go", "virtual_map_test.go", ], diff --git a/pkg/sentry/platform/kvm/kvm_amd64_test.go b/pkg/sentry/platform/kvm/kvm_amd64_test.go index e44e995a0..382953cf7 100644 --- a/pkg/sentry/platform/kvm/kvm_amd64_test.go +++ b/pkg/sentry/platform/kvm/kvm_amd64_test.go @@ -49,3 +49,33 @@ func TestSegments(t *testing.T) { return false }) } + +// stmxcsr reads the MXCSR control and status register. +func stmxcsr(addr *uint32) + +func TestMXCSR(t *testing.T) { + applicationTest(t, true, testutil.SyscallLoop, func(c *vCPU, regs *arch.Registers, pt *pagetables.PageTables) bool { + var si arch.SignalInfo + switchOpts := ring0.SwitchOpts{ + Registers: regs, + FloatingPointState: &dummyFPState, + PageTables: pt, + FullRestore: true, + } + mxcsrBefore := uint32(0) + mxcsrAfter := uint32(0) + stmxcsr(&mxcsrBefore) + switchOpts.FloatingPointState.SetMXCSR(mxcsrBefore ^ 0x8) + if _, err := c.SwitchToUser( + switchOpts, &si); err == platform.ErrContextInterrupt { + return true // Retry. + } else if err != nil { + t.Errorf("application syscall failed: %v", err) + } + stmxcsr(&mxcsrAfter) + if mxcsrAfter != mxcsrBefore { + t.Errorf("mxcsr = %x (expected %x)", mxcsrBefore, mxcsrAfter) + } + return false + }) +} diff --git a/pkg/sentry/platform/kvm/kvm_amd64_test.s b/pkg/sentry/platform/kvm/kvm_amd64_test.s new file mode 100644 index 000000000..8e9079867 --- /dev/null +++ b/pkg/sentry/platform/kvm/kvm_amd64_test.s @@ -0,0 +1,21 @@ +// 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. + +#include "textflag.h" + +// stmxcsr reads the MXCSR control and status register. +TEXT ·stmxcsr(SB),NOSPLIT,$0-8 + MOVQ addr+0(FP), SI + STMXCSR (SI) + RET -- cgit v1.2.3