mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
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
This commit is contained in:
@@ -250,6 +250,7 @@ func (c *CPU) SwitchToUser(switchOpts SwitchOpts) (vector Vector) {
|
||||
}
|
||||
SaveFloatingPoint(switchOpts.FloatingPointState.BytePointer()) // escapes: no. Copy out floating point.
|
||||
WriteFS(uintptr(c.registers.Fs_base)) // escapes: no. Restore kernel FS.
|
||||
ldmxcsr(&kernelMXCSR) // escapes: no. Restore kernel MXCSR.
|
||||
return
|
||||
}
|
||||
|
||||
@@ -321,3 +322,13 @@ func SetCPUIDFaulting(on bool) bool {
|
||||
func ReadCR2() uintptr {
|
||||
return readCR2()
|
||||
}
|
||||
|
||||
// kernelMXCSR is the value of the mxcsr register in the Sentry.
|
||||
//
|
||||
// The MXCSR control configuration is initialized once and never changed. Look
|
||||
// at src/cmd/compile/abi-internal.md in the golang sources for more details.
|
||||
var kernelMXCSR uint32
|
||||
|
||||
func init() {
|
||||
stmxcsr(&kernelMXCSR)
|
||||
}
|
||||
|
||||
@@ -61,6 +61,12 @@ func wrgsbase(addr uintptr)
|
||||
// wrgsmsr writes to the GS_BASE MSR.
|
||||
func wrgsmsr(addr uintptr)
|
||||
|
||||
// stmxcsr reads the MXCSR control and status register.
|
||||
func stmxcsr(addr *uint32)
|
||||
|
||||
// ldmxcsr writes to the MXCSR control and status register.
|
||||
func ldmxcsr(addr *uint32)
|
||||
|
||||
// readCR2 reads the current CR2 value.
|
||||
func readCR2() uintptr
|
||||
|
||||
|
||||
@@ -198,3 +198,15 @@ TEXT ·rdmsr(SB),NOSPLIT,$0-16
|
||||
MOVL AX, ret+8(FP)
|
||||
MOVL DX, ret+12(FP)
|
||||
RET
|
||||
|
||||
// stmxcsr reads the MXCSR control and status register.
|
||||
TEXT ·stmxcsr(SB),NOSPLIT,$0-8
|
||||
MOVQ addr+0(FP), SI
|
||||
STMXCSR (SI)
|
||||
RET
|
||||
|
||||
// ldmxcsr writes to the MXCSR control and status register.
|
||||
TEXT ·ldmxcsr(SB),NOSPLIT,$0-8
|
||||
MOVQ addr+0(FP), SI
|
||||
LDMXCSR (SI)
|
||||
RET
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user