diff --git a/pkg/ring0/kernel_amd64.go b/pkg/ring0/kernel_amd64.go index 4b8e5aa43..ab20712b5 100644 --- a/pkg/ring0/kernel_amd64.go +++ b/pkg/ring0/kernel_amd64.go @@ -315,27 +315,6 @@ func startGo(c *CPU) { wrmsr(_MSR_CSTAR, kernelFunc(addrOfSysenter())) } -// SetCPUIDFaulting sets CPUID faulting per the boolean value. -// -// True is returned if faulting could be set. -// -//go:nosplit -func SetCPUIDFaulting(on bool) bool { - // Per the SDM (Vol 3, Table 2-43), PLATFORM_INFO bit 31 denotes support - // for CPUID faulting, and we enable and disable via the MISC_FEATURES MSR. - if rdmsr(_MSR_PLATFORM_INFO)&_PLATFORM_INFO_CPUID_FAULT != 0 { - features := rdmsr(_MSR_MISC_FEATURES) - if on { - features |= _MISC_FEATURE_CPUID_TRAP - } else { - features &^= _MISC_FEATURE_CPUID_TRAP - } - wrmsr(_MSR_MISC_FEATURES, features) - return true // Setting successful. - } - return false -} - // ReadCR2 reads the current CR2 value. // //go:nosplit diff --git a/pkg/ring0/x86.go b/pkg/ring0/x86.go index 469c67401..2668ce9ca 100644 --- a/pkg/ring0/x86.go +++ b/pkg/ring0/x86.go @@ -52,16 +52,10 @@ const ( _EFER_LMA = 0x400 _EFER_NX = 0x800 - _MSR_STAR = 0xc0000081 - _MSR_LSTAR = 0xc0000082 - _MSR_CSTAR = 0xc0000083 - _MSR_SYSCALL_MASK = 0xc0000084 - _MSR_PLATFORM_INFO = 0xce - _MSR_MISC_FEATURES = 0x140 - - _PLATFORM_INFO_CPUID_FAULT = 1 << 31 - - _MISC_FEATURE_CPUID_TRAP = 0x1 + _MSR_STAR = 0xc0000081 + _MSR_LSTAR = 0xc0000082 + _MSR_CSTAR = 0xc0000083 + _MSR_SYSCALL_MASK = 0xc0000084 ) const ( diff --git a/pkg/sentry/platform/kvm/machine_amd64.go b/pkg/sentry/platform/kvm/machine_amd64.go index cb75ddf3c..5aecfc670 100644 --- a/pkg/sentry/platform/kvm/machine_amd64.go +++ b/pkg/sentry/platform/kvm/machine_amd64.go @@ -22,17 +22,18 @@ import ( "math/big" "reflect" "runtime" - "runtime/debug" "golang.org/x/sys/unix" "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/cpuid" "gvisor.dev/gvisor/pkg/hostarch" "gvisor.dev/gvisor/pkg/hostsyscall" + "gvisor.dev/gvisor/pkg/log" "gvisor.dev/gvisor/pkg/ring0" "gvisor.dev/gvisor/pkg/ring0/pagetables" "gvisor.dev/gvisor/pkg/sentry/platform" ktime "gvisor.dev/gvisor/pkg/sentry/time" + "gvisor.dev/gvisor/pkg/sync" ) // initArchState initializes architecture-specific state. @@ -54,22 +55,6 @@ func (m *machine) initArchState() error { } m.mu.Unlock() - c := m.Get() - defer m.Put(c) - // Enable CPUID faulting, if possible. Note that this also serves as a - // basic platform sanity tests, since we will enter guest mode for the - // first time here. The recovery is necessary, since if we fail to read - // the platform info register, we will retry to host mode and - // ultimately need to handle a segmentation fault. - old := debug.SetPanicOnFault(true) - defer func() { - recover() - debug.SetPanicOnFault(old) - }() - - bluepill(c) - ring0.SetCPUIDFaulting(true) - return nil } @@ -97,6 +82,8 @@ const ( poolPCIDs = 8 ) +var cpuidFaultingWarnOnce sync.Once + // initArchState initializes architecture-specific state. func (c *vCPU) initArchState() error { var ( @@ -158,7 +145,22 @@ func (c *vCPU) initArchState() error { } // Set the time offset to the host native time. - return c.setSystemTime() + if err := c.setSystemTime(); err != nil { + return err + } + + // Try to enable CPUID faulting. This is required to handle app CPUID + // correctly, since we always pass the CPUID returned by + // KVM_GET_SUPPORTED_CPUID to KVM_SET_CPUID2. Note that while hardware + // support for CPUID faulting is inconsistent, KVM always supports it after + // db2336a80489e ("KVM: x86: virtualize cpuid faulting"), Linux 4.12+. + if err := c.enableCPUIDFaulting(); err != nil { + cpuidFaultingWarnOnce.Do(func() { + log.Warningf("Application CPUID will be incorrect: %v", err) + }) + } + + return nil } // bitsForScaling returns the bits available for storing the fraction component diff --git a/pkg/sentry/platform/kvm/machine_amd64_unsafe.go b/pkg/sentry/platform/kvm/machine_amd64_unsafe.go index 0d2878002..e37bd6d3f 100644 --- a/pkg/sentry/platform/kvm/machine_amd64_unsafe.go +++ b/pkg/sentry/platform/kvm/machine_amd64_unsafe.go @@ -140,6 +140,26 @@ func (c *vCPU) setTSC(value uint64) error { return nil } +func (c *vCPU) enableCPUIDFaulting() error { + const ( + _MSR_MISC_FEATURES_ENABLE = 0x140 + _MSR_MISC_FEATURES_ENABLES_CPUID_FAULT = 1 << 0 + ) + registers := modelControlRegisters{ + nmsrs: 1, + } + registers.entries[0].index = _MSR_MISC_FEATURES_ENABLE + registers.entries[0].data = _MSR_MISC_FEATURES_ENABLES_CPUID_FAULT + if errno := hostsyscall.RawSyscallErrno( + unix.SYS_IOCTL, + uintptr(c.fd), + KVM_SET_MSRS, + uintptr(unsafe.Pointer(®isters))); errno != 0 { + return fmt.Errorf("error enabling CPUID faulting: %v", errno) + } + return nil +} + // setUserRegisters sets user registers in the vCPU. // //go:nosplit